home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d2 / v8n12.arc / EMS40.ASM < prev    next >
Assembly Source File  |  1989-04-05  |  77KB  |  2,128 lines

  1. ;============================================================================
  2. ;EMS40.SYS an Expanded Memory Simulator for the IBM AT
  3. ;============================================================================
  4.         PAGE    ,132
  5. CODE        SEGMENT PUBLIC'code'
  6.         ASSUME    CS:CODE
  7. ;-----------------------------------------------------------------------------
  8. ;Structure of the device driver request header
  9. ;-----------------------------------------------------------------------------
  10. REQ_STRUC    STRUC
  11. LEN        DB    ?
  12. UNIT        DB    ?            ;unit number
  13. COMMAND        DB    ?            ;command code
  14. STATUS        DW    ?            ;return status
  15. RESERVE        DB    8 DUP (?)
  16. MEDIA        DB    ?
  17. ADDRESS        DD    ?            ;Transfer address
  18. CONFIG_PTR    DD    ?            ;Pointer to line in config
  19. REQ_STRUC    ENDS
  20. ;-----------------------------------------------------------------------------
  21. ;Segment descriptor structure
  22. ;-----------------------------------------------------------------------------
  23. DAT_SEG_DES    STRUC                ;data segment descriptor
  24. SEG_LIM        DW    0            ;length of segment
  25. BASE_ADRL    DW    0            ;base address of segment
  26. BASE_ADRH    DB    0
  27.         DB    0            ;access rights byte
  28.         DW    0            ;reserved
  29. DAT_SEG_DES    ENDS
  30. ;=============================================================================
  31. ;Device header begin
  32. ;=============================================================================
  33.         ORG    0            ;drivers start at offset 0
  34. HEADER        DD    -1                      ;Pointer to next driver
  35.         DW    8000H            ;device attribute word
  36.         DW    OFFSET STRATEGY        ;pointer to strategy routine
  37.         DW    OFFSET INTERRUPT        ;pointer to interrupt routine
  38.         DB    'EMMXXXX0'        ;name of driver
  39. ;Device header end
  40. SWAP_POINTER    DW    OFFSET EMS_EXCH_PAG
  41. PROGRAM        DB    "EMS 4.0 Simulator"
  42. COPYRIGHT    DB    " (C) 1989 Ziff Communications",13,10
  43. PROGRAMMER    DB    "PC Magazine ",254," Douglas Boling",13,10,"$",26
  44. REQ_HEADADR    DD    ?            ;Far pointer to request header
  45. ;-----------------------------------------------------------------------------
  46. ;Global Descriptor table needed for moves to and from extended memory.
  47. ;-----------------------------------------------------------------------------
  48. GDT        LABEL    BYTE
  49.         DAT_SEG_DES <>            ;Dummy
  50.         DAT_SEG_DES <>            ;GDT descriptor
  51. SOURCE        DAT_SEG_DES <4000H,,,93H,>    ;source descriptor
  52. DEST        DAT_SEG_DES <4000H,,,93H,>    ;destination descriptor
  53.         DAT_SEG_DES <>            ;bios code descriptor
  54.         DAT_SEG_DES <>            ;stack segment descriptor
  55. ;=============================================================================
  56. ;Strategy routine. This routine stores the address of the request header
  57. ;=============================================================================
  58. STRATEGY    PROC    FAR
  59.         ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
  60.         MOV    WORD PTR CS:[REQ_HEADADR],BX    ;save offset
  61.         MOV    WORD PTR CS:[REQ_HEADADR+2],ES    ;save segment
  62.         RET
  63. STRATEGY    ENDP
  64. ;=============================================================================
  65. ;Interrupt routine. This routine executes the command code in the req header.
  66. ;=============================================================================
  67. INTERRUPT    PROC    FAR
  68.         ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
  69.         PUSHF
  70.         PUSH    AX            ;save every register used
  71.         PUSH    BX
  72.         PUSH    CX
  73.         PUSH    DX
  74.         PUSH    DI
  75.         PUSH    SI
  76.         PUSH    DS
  77.         PUSH    ES
  78.         PUSH    CS            ;Set DS
  79.         POP    DS
  80.         ASSUME DS:CODE
  81.         CLD                ;any string operations move up.
  82. ;Get command from request header
  83.         LES    DI,[REQ_HEADADR]    ;load address of req header
  84.         ASSUME    ES:NOTHING
  85.         MOV    BL,ES:[DI.COMMAND]
  86.         CMP    BL,0
  87.         JNE    PROCESS1
  88.         CALL    INITIALIZE
  89.         JMP    SHORT DONE
  90. PROCESS1:    CMP    BL,16            ;see if command out of range
  91.         JBE    DONE
  92.         MOV    AX,8003H        ;unknown command error code
  93. DONE:        OR    AX,0100H        ;set the 'done' bit
  94.         MOV    ES:[DI.STATUS],AX
  95.         POP    ES            ;restore registers before exit
  96.         POP    DS
  97.         POP    SI
  98.         POP    DI
  99.         POP    DX
  100.         POP    CX
  101.         POP    BX
  102.         POP    AX
  103.         POPF
  104.         RET
  105. INTERRUPT    ENDP
  106. DRIVER_END    =    $            ;Last part of driver code
  107. ;======================================================================
  108. ;EMS Driver code starts here.
  109. ;======================================================================
  110. OLD_INT15H    LABEL DWORD
  111. OLD_INT15HO    DW    ?            ;offset of old interrupt vector
  112. OLD_INT15HS    DW    ?            ;segment
  113. EXT_MEM_LIMIT    DW    0            ;adjusted top of avail memory
  114. OS_ENABLED    DB    1            ;Enable os functions 1=enabled
  115. OS_PASS_LOW    DW    0            ;Operating system password.
  116. OS_PASS_HIGH     DW    0
  117. ALT_MAP_PTRS     DW    0            ;Mapping pointer for funct 28
  118. ALT_MAP_PTRO     DW    0
  119. WINDOW_SEG    DW    ?            ;starting segment of ems win
  120. WINDOW_ADDR_BASE    DD    4 DUP(0)    ;address of each page
  121. EXTEND_ADRL    DW    ?            ;base of extended memory used
  122. EXTEND_ADRH    DB    ?
  123. TOTAL_PAGES    DW    24            ;default to 384k of exp mem.
  124. TOTAL_HANDLES    DW    255            ;Default number of handles
  125. PAG_OWNER_TBL    DW    ?            ;Pointer to page table
  126. HANDLE_ARRAY     DW    ?                       ;Pointer to handle table
  127. MAP_ARRAY_PTR     DW    ?                       ;Pointer to map array
  128.  
  129. ACTIVE        DB    0            ;Active flag
  130.  
  131.  
  132. ;======================================================================
  133. ;Interrupt 15h routine. Intercept extended memory size determine.
  134. ;======================================================================
  135. INT_15H        PROC    FAR
  136.         ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
  137.         CMP    AH,88H
  138.         JE    INT15_F88
  139.         JMP    CS:[OLD_INT15H]
  140. INT15_F88:    MOV    AX,CS:EXT_MEM_LIMIT             ;provide new limit
  141.         CLC                                     ;clear error flag
  142.         RET    2
  143. INT_15H        ENDP
  144. ;-----------------------------------------------------------------------------
  145. ;Jump table for EMS driver commands
  146. ;-----------------------------------------------------------------------------
  147. EMS_CMDS    DW    OFFSET EMS_01        ;Get status
  148.         DW    OFFSET EMS_02        ;Get page frame seg address
  149.         DW    OFFSET EMS_03        ;Get unallocated page count
  150.         DW    OFFSET EMS_04        ;Allocate pages
  151.         DW    OFFSET EMS_05        ;Map/unmap handle pages
  152.         DW    OFFSET EMS_06        ;Deallocate pages
  153.         DW    OFFSET EMS_07        ;Get version
  154.         DW    OFFSET EMS_08        ;Save page map
  155.         DW    OFFSET EMS_09        ;Restore page map
  156.         DW    OFFSET EMS_UNSP        ;reserved
  157.         DW    OFFSET EMS_UNSP        ;reserved
  158.         DW    OFFSET EMS_12        ;Get handle count
  159.         DW    OFFSET EMS_13        ;Get handle pages
  160.         DW    OFFSET EMS_14        ;Get all handle pages
  161.         DW    OFFSET EMS_15        ;Page map functions
  162.         DW    OFFSET EMS_16        ;Partial page map functions
  163.         DW    OFFSET EMS_17        ;Map/unmap multiple hndl pages
  164.         DW    OFFSET EMS_18        ;Reallocate pages
  165.         DW    OFFSET EMS_19        ;Handle attribute
  166.         DW    OFFSET EMS_20        ;Handle name
  167.         DW    OFFSET EMS_21        ;Handle directory
  168.         DW    OFFSET EMS_22        ;Alter page map and jump
  169.         DW    OFFSET EMS_23        ;Alter page map and call
  170.         DW    OFFSET EMS_24        ;move/exchange memory region
  171.         DW    OFFSET EMS_25        ;Get mappable phys addr array
  172.         DW    OFFSET EMS_26        ;Hardware configuration
  173.         DW    OFFSET EMS_27        ;Allocate standard pages
  174.         DW    OFFSET EMS_28        ;Alternate map register set
  175.         DW    OFFSET EMS_UNSP        ;Warmboot preparation
  176.         DW    OFFSET EMS_30        ;OS/E functions
  177. ;======================================================================
  178. ;Interrupt 67h routine. EMS driver function dispatcher.
  179. ;======================================================================
  180. INT_67H        PROC    FAR
  181.         ASSUME     CS:CODE,DS:NOTHING,ES:NOTHING
  182.         PUSH    BP
  183.         MOV    BP,SP            ;set up stack addressing
  184.         STI                ;allow interrupts
  185.         CLD                ;any string operations move up.
  186.         PUSH    CX            ;Save registers
  187.         PUSH    DI            ;NOTE: Don't change the
  188.         PUSH    SI                      ;  order of the register save.
  189.         PUSH    DS                      ;  Many of the routines depend
  190.         PUSH    ES                      ;  on the correct order.
  191.         PUSH    CS            ;point ds to code segment
  192.         POP    DS
  193.         ASSUME DS:CODE
  194.         CMP    AH,5DH            ;Check for a cmd out of range
  195.         JA    EMS_CMD_ERR
  196.         CMP    AH,40H
  197.         JL    EMS_CMD_ERR
  198.         MOV    DI,OFFSET RETURN_ADDR    ;Push return address onto
  199.         PUSH    DI            ;  stack.
  200.         PUSH    AX            ;save ax
  201.         SUB    AH,40H            ;Convert command code in AX
  202.         MOV    AL,AH            ;  into a jump address.
  203.         XOR    AH,AH                   ;Clear upper byte
  204.         SAL    AX,1            ;Convert to word offset
  205.         ADD    AX,OFFSET EMS_CMDS    ;add offset of jump table
  206.         MOV    DI,AX            ;Copy to DI
  207.         POP    AX            ;restore AX
  208.         PUSH    [DI]            ;Put offset of routine on stk
  209.         MOV    DI,[BP-4]        ;Restore DI
  210.         CALL    EMS_CHECK_HDL           ;check for valid handle in DX
  211.         RETN                ;Use ret to call function.
  212. RETURN_ADDR:    POP    ES            ;Restore registers
  213.         POP    DS
  214.         POP    SI
  215.         POP    DI
  216.         POP    CX
  217.         POP    BP
  218. EMS_I67_EXIT:
  219.         IRET
  220. EMS_CMD_ERR:    MOV    AH,84H                  ;EMS command out of range
  221.         JMP    SHORT RETURN_ADDR
  222. INT_67H        ENDP
  223. ;======================================================================
  224. ;Function 1.  Get status.
  225. ;======================================================================
  226. EMS_01        PROC    NEAR
  227.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  228.         XOR    AX,AX
  229.         RET
  230. EMS_01        ENDP
  231. ;======================================================================
  232. ;Function 2.  Get segment address of EMS window
  233. ;======================================================================
  234. EMS_02        PROC    NEAR
  235.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  236.         MOV    BX,WINDOW_SEG        ;store starting seg of window
  237.         XOR    AX,AX
  238.         RET
  239. EMS_02        ENDP
  240. ;======================================================================
  241. ;Function 3.  Get count of unallocated pages
  242. ;======================================================================
  243. EMS_03        PROC    NEAR
  244.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  245.         XOR    DX,DX            ;search for hndl =-1 (unaloc)
  246.         DEC    DX
  247.         CLC                ;fake 'handle ok' flag
  248.         CALL    EMS_13
  249.         MOV    DX,TOTAL_PAGES        ;Load total pages
  250.         XOR    AX,AX             ;Clear return code
  251.         RET
  252. EMS_03        ENDP
  253. ;======================================================================
  254. ;Function 4.  Get handle and allocate pages
  255. ;======================================================================
  256. EMS_04        PROC    NEAR
  257.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  258.         OR    BX,BX            ;Check for 0 page request
  259.         JE    EMS_04_ERR        ;If so, error
  260.         CALL    EMS_27            ;Let function 27 do the work
  261. EMS_04_EXIT:    RET
  262. EMS_04_ERR:    MOV    AH,89H            ;attempt to allocate 0 pages
  263.         JMP    SHORT EMS_04_EXIT
  264. EMS_04        ENDP
  265. ;======================================================================
  266. ;Function 5,  Map / Unmap pages.
  267. ;======================================================================
  268. EMS_05        PROC    NEAR
  269.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  270.         PUSH    BX
  271.         PUSH    DX
  272.         JC    EMS_05_EXIT        ;carry set, invalid handle
  273.         CMP    AL,3            ;Check for physical page out
  274.         JG    EMS_05_ERR0        ;  of range
  275.         CMP    BX,0FFFFH        ;See if unmap page. If so,
  276.         JNE    EMS_05_S1        ;  save current mapped page
  277.         MOV    BL,AL                   ;  but don't map new page.
  278.         XOR    AX,AX
  279.         XOR    DX,DX                   ;DL:AX=0 indicates no map
  280.         JMP    SHORT EMS_05_S2
  281. EMS_05_S1:    PUSH    AX            ;Save physical page to map
  282.         CALL    EMS_LOG2PHY        ;Convert page into an address
  283.         POP    BX                      ;Put phy page into BX for call
  284.         JC    EMS_05_EXIT        ;If error, exit
  285. EMS_05_S2:    CALL    EMS_EXCH_PAG        ;Map the page
  286.                  XOR    AX,AX            ;Clear return code
  287. EMS_05_EXIT:    POP    DX                      ;Restore registers.
  288.         POP    BX
  289.         RET
  290. EMS_05_ERR0:    MOV    AH,8BH            ;Physical page out of range
  291.         JMP    SHORT EMS_05_EXIT
  292. EMS_05        ENDP
  293. ;======================================================================
  294. ;Function 6,  Deallocate pages.
  295. ;======================================================================
  296. EMS_06        PROC    NEAR
  297.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  298.         PUSH    BX
  299.         PUSH    DX
  300.         JC    EMS_06_EXIT        ;carry set, invalid handle
  301.         MOV    BL,0FFH            ;clear all pages
  302.         CALL    EMS_DEALLOC        ;Deallocate memory
  303.         OR    DL,DL            ;handle zero cannot be
  304.         JE    EMS_06_GOOD        ;  deallocated
  305.         PUSH    CS                      ;Deallocate handle
  306.         POP    ES
  307.         ASSUME    ES:CODE
  308.         MOV    DI,HANDLE_ARRAY
  309.         MOV    AX,DX            ;copy handle
  310.         MOV    CX,9            ;convert handle to an index into
  311.         MUL    CX            ;  the handle array.
  312.         ADD    DI,AX
  313.         XOR    AL,AL            ;Erase handle flag and name.
  314.         REP    STOSB
  315. EMS_06_GOOD:    XOR    AX,AX            ;clear return code
  316. EMS_06_EXIT:    POP    DX
  317.         POP    BX
  318.         RET
  319. EMS_06        ENDP
  320. ;======================================================================
  321. ;Function 7.  Get version number
  322. ;======================================================================
  323. EMS_07        PROC    NEAR
  324.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  325.         MOV    AX,0040H        ;store ver num and ret code
  326.         RET
  327. EMS_07        ENDP
  328. ;======================================================================
  329. ;Function 8. Save page map.
  330. ;======================================================================
  331. EMS_08        PROC    NEAR
  332.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  333.         PUSH    BX
  334.         PUSH    DX
  335.         JC    EMS_08_EXIT        ;carry set, invalid handle
  336. ;Search the mapping arrays to find an array that is empty.  At the same
  337. ;   time, make sure that the handle doesn't have an array currently saved.
  338.         MOV    SI,MAP_ARRAY_PTR    ;start search of map arr lbls
  339.         MOV    CX,3            ;search all 3 save map arrays
  340.         XOR    BX,BX            ;initialize free pointer
  341. EMS_08_L1:    ADD    SI,18            ;look at next map array
  342.         CMP    WORD PTR [SI],0    ;see if free
  343.         JNE    EMS_08_S1
  344.         MOV    DI,SI            ;if so, copy address
  345.         JMP    SHORT EMS_08_S3
  346. EMS_08_S1:    CMP    [SI],DX            ;see if curr hndl used before
  347.         JNE    EMS_08_S2
  348.         MOV    AH,8DH            ;handle already used for save
  349.         JMP    SHORT EMS_08_EXIT
  350. EMS_08_S2:    LOOP    EMS_08_L1        ;loop back if less than 4 times
  351.         MOV    AH,8CH            ;no room to store page map
  352.         JMP    SHORT EMS_08_EXIT
  353. EMS_08_S3:    PUSH    CS            ;point ds:si to page array
  354.         POP    ES
  355.         ASSUME ES:CODE            ;point es:di to save array
  356.         MOV    SI,MAP_ARRAY_PTR
  357.         MOV    [SI],DX            ;label arrays with handle
  358.         MOV    CX,9
  359.         REP    MOVSW
  360.         XOR    AX,AX            ;clear return code
  361. EMS_08_EXIT:    POP    DX
  362.                 POP    BX
  363.         RET
  364. EMS_08        ENDP
  365. ;======================================================================
  366. ;Function 9. Restore page map
  367. ;======================================================================
  368. EMS_09        PROC    NEAR
  369.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  370.         PUSH    BX
  371.         PUSH    DX
  372.         JC    EMS_09_EXIT        ;carry set, invalid handle
  373. ;find the saved page map in the save array.
  374.         MOV    SI,MAP_ARRAY_PTR
  375.         MOV    CX,3
  376. EMS_09_L1:    ADD    SI,18            ;look at next map array
  377.         CMP    [SI],DX            ;See if array label matches the
  378.         JE    EMS_09_S1        ;  handle.
  379.         LOOP    EMS_09_L1
  380.         MOV    AH,8EH            ;no saved page map found
  381.         JMP    SHORT EMS_09_EXIT
  382. ;Now that the saved array has been found, call restore map routine.
  383. EMS_09_S1:    MOV    WORD PTR [SI],0        ;mark saved array as free
  384.         CALL    EMS_15_1        ;restore map
  385.         XOR    AX,AX            ;clear return code
  386. EMS_09_EXIT:    POP    DX
  387.         POP    BX
  388.         RET
  389. EMS_09        ENDP
  390. ;======================================================================
  391. ;Function 12, Get Handle Count
  392. ;======================================================================
  393. EMS_12        PROC    NEAR
  394.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  395.         MOV    DI,HANDLE_ARRAY        ;point to handle array
  396.         XOR    BX,BX            ;clear count and compare regs
  397.         MOV    CX,TOTAL_HANDLES    ;look at all handles 0 - feh
  398. EMS_12_L1:    CMP    BH,[DI]            ;if handle id = 0 then that
  399.         JE    EMS_12_S1        ;  handle has not been allocated.
  400.         INC    BL            ;Add one to open handle count
  401. EMS_12_S1:    ADD    DI,9            ;Move di to point to next id.
  402.         LOOP    SHORT EMS_12_L1
  403.         XOR    AX,AX            ;clear return code
  404. EMS_12_EXIT:    RET
  405. EMS_12        ENDP
  406. ;======================================================================
  407. ;Function 13 Get Handle pages
  408. ;Entry: dx = handle to search for
  409. ;Exit:  ax = return code.      bx = number of matches found.
  410. ;======================================================================
  411. EMS_13        PROC    NEAR
  412.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  413.         PUSH    DI
  414.         JC    EMS_13_EXIT        ;carry set, invalid handle
  415.         MOV    DI,PAG_OWNER_TBL    ;point to owner table
  416.         MOV    CX,TOTAL_PAGES
  417.         XOR    BX,BX            ;Clear page count
  418. EMS_13_LOOP:    CMP    DL,[DI]            ;Compare handle to table
  419.         JNE    EMS_13_SKIP
  420.         INC    BX                      ;Inc count of pages
  421. EMS_13_SKIP:    ADD    DI,3            ;Point to next entry
  422.         LOOP    EMS_13_LOOP
  423.         XOR    AX,AX                   ;Clear return code.
  424. EMS_13_EXIT:    POP    DI
  425.         RET
  426. EMS_13        ENDP
  427. ;======================================================================
  428. ;Function 14. Get All Handle Pages
  429. ;======================================================================
  430. EMS_14        PROC    NEAR
  431.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  432.         PUSH    DX
  433.         XOR    DX,DX            ;handle currently being checked
  434.         XOR    SI,SI            ;si total open handles counter
  435. EMS_14_L1:    CALL    EMS_CHECK_HDL        ;see if handle active
  436.         CALL    EMS_13            ;cnt number of pages for hdl
  437.         JC    EMS_14_S1               ;if bad handle, skip
  438.         INC    SI            ;add to handle count
  439.         MOV    ES:[DI],DX        ;write results to the array
  440.         MOV    ES:2[DI],BX
  441. EMS_14_S1:    INC    DX            ;point to next handle
  442.         ADD    DI,4            ;incriment array pointer
  443.         CMP    DX,TOTAL_HANDLES    ;have we check all handles?
  444.         JL    EMS_14_L1        ;no, loop back.
  445.         MOV    BX,SI            ;Get number of active handles
  446.         XOR    AX,AX            ;clear return code
  447. EMS_14_EXIT:    POP    DX
  448.         RET
  449. EMS_14        ENDP
  450. ;======================================================================
  451. ;Function 15.  Get/Set Page Map
  452. ;======================================================================
  453. EMS_15_TBL    DW    OFFSET EMS_15_0    ;Jump table for subfunctions
  454.         DW    OFFSET EMS_15_1
  455.         DW    OFFSET EMS_15_2
  456.         DW    OFFSET EMS_15_3
  457. EMS_15        PROC    NEAR
  458.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  459.         PUSH    BX
  460.         PUSH    DX
  461.         PUSH    DS
  462.         MOV    DS,SS:[BP-8]        ;Get original DS
  463.         ASSUME DS:NOTHING
  464.         CMP    AL,3            ;check al for a number not 0-3
  465.         JA    EMS_15_ERROR
  466.         XOR    AH,AH            ;clear top byte of subfunction
  467.         MOV    BX,AX            ;convert into jump address
  468.         SAL    BX,1
  469.         ADD    BX,OFFSET EMS_15_TBL
  470.         CALL    CS:[BX]
  471. EMS_15_EXIT:    POP    DS
  472.         POP    DX
  473.         POP    BX
  474.         RET
  475. EMS_15_ERROR:    MOV    AH,8FH            ;invalid subfunction
  476.         JMP    SHORT EMS_15_EXIT
  477. EMS_15        ENDP
  478. ;----------------------------------------------------------------------
  479. ;Function 15.0  Get mapping array
  480. ;----------------------------------------------------------------------
  481. EMS_15_0    PROC    NEAR
  482.         ASSUME DS:NOTHING,ES:NOTHING
  483.         PUSH    SI
  484.         PUSH    DS
  485.         PUSH    CS
  486.         POP    DS
  487.         ASSUME DS:CODE
  488.         MOV    SI,MAP_ARRAY_PTR    ;ds:si points to page array
  489.         MOV    CX,9            ;es:di points to destination
  490.         REP    MOVSW            ;copy mapping array
  491.         XOR    AH,AH
  492.         POP    DS
  493.         POP    SI
  494.         RET
  495. EMS_15_0    ENDP
  496. ;----------------------------------------------------------------------
  497. ;Function 15.1  Set mapping array
  498. ;----------------------------------------------------------------------
  499. EMS_15_1    PROC    NEAR
  500.         ASSUME DS:NOTHING,ES:NOTHING
  501.         PUSH    SI
  502.         XOR    BX,BX            ;start with logical page 0
  503.         ADD    SI,2            ;move si past the handle pointer
  504. EMS_15_1_L1:    MOV    AX,DS:[SI]        ;get current page address
  505.         MOV    DX,DS:2[SI]
  506.         PUSH    BX
  507.         CALL    EMS_EXCH_PAG        ;Exchange current window page
  508.         POP    BX                      ;Point si to next address
  509.         ADD    SI,4
  510.         INC    BX
  511.         CMP    BL,3            ;Have we done all 4 pages?
  512.         JLE    EMS_15_1_L1        ;No, loop back
  513.         XOR    AH,AH
  514. EMS_15_1_EXIT:    POP    SI
  515.         RET
  516. EMS_15_1    ENDP
  517. ;----------------------------------------------------------------------
  518. ;Function 15.2  Get & Set mapping array
  519. ;----------------------------------------------------------------------
  520. EMS_15_2    PROC    NEAR
  521.         ASSUME DS:NOTHING,ES:NOTHING
  522.         PUSH    DI
  523.         CALL    EMS_15_0        ;Save current mapping array
  524.         POP    DI
  525.         CALL    EMS_15_1        ;Set new mapping context
  526.         XOR    AH,AH
  527.         RET
  528. EMS_15_2    ENDP
  529. ;----------------------------------------------------------------------
  530. ;Function 15.3  Get mapping array size
  531. ;----------------------------------------------------------------------
  532. EMS_15_3    PROC    NEAR
  533.         ASSUME DS:NOTHING,ES:NOTHING
  534.         MOV    AX,0012H        ;18 bytes in the page array
  535.         RET
  536. EMS_15_3    ENDP
  537. ;======================================================================
  538. ;Function 16.  Get/Set Partial Page Map
  539. ;======================================================================
  540. EMS_16_TBL    DW    OFFSET EMS_16_0        ;Jump table for subfunctions
  541.         DW    OFFSET EMS_16_1
  542.         DW    OFFSET EMS_16_2
  543. EMS_16        PROC    NEAR
  544.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  545.         PUSH    BX
  546.         PUSH    DX
  547.         PUSH    DS
  548.         MOV    DS,SS:[BP-8]        ;Get original DS from stack
  549.         ASSUME DS:NOTHING
  550. EMS_16_S1:    XOR    AH,AH            ;clear top byte of subfunction
  551.         CMP    AL,2            ;check al for a number not 0-3
  552.         JA    EMS_16_ERROR
  553.         MOV    DI,AX            ;convert into jump address
  554.         SAL    DI,1
  555.         ADD    DI,OFFSET EMS_16_TBL
  556.         CALL    CS:[DI]
  557. EMS_16_EXIT:    POP    DS
  558.         POP    DX
  559.         POP    BX
  560.         RET
  561. EMS_16_ERROR:    MOV    AH,8FH            ;invalid subfunction
  562.         JMP    SHORT EMS_16_EXIT
  563. EMS_16        ENDP
  564. ;----------------------------------------------------------------------
  565. ;Function 16.0  Get mapping array
  566. ;----------------------------------------------------------------------
  567. EMS_16_0    PROC    NEAR
  568.         ASSUME DS:NOTHING,ES:NOTHING
  569.         MOV    DI,SS:[BP-4]        ;Get back original DI.
  570.         MOV    CX,DS:[SI]        ;get count of mappable segs.
  571.         MOV    ES:[DI],CX        ;save count
  572. EMS_16_0_L1:    MOV    AX,DS:2[SI]        ;Get segment to convert
  573.         CALL    EMS_SEG2LOG        ;convert segment onto page #
  574.         JC    EMS_16_0_EXIT
  575.         MOV    ES:2[DI],BX        ;save physical page number
  576.         SAL    BX,1            ;Convert page number
  577.         SAL    BX,1            ;  into offset
  578.         ADD    BX,CS:MAP_ARRAY_PTR
  579.         MOV    AX,CS:2[BX]
  580.         MOV    ES:4[DI],AX        ;save address low
  581.         MOV    AX,CS:4[BX]
  582.         MOV    ES:6[DI],AX        ;save address high
  583.         ADD    DI,6
  584.         INC    SI            ;point to next seg to save
  585.         INC    SI
  586.         LOOP    EMS_16_0_L1
  587.         XOR    AX,AX
  588. EMS_16_0_EXIT:    RET
  589. EMS_16_0    ENDP
  590. ;----------------------------------------------------------------------
  591. ;Function 16.1  Set mapping array
  592. ;----------------------------------------------------------------------
  593. EMS_16_1    PROC    NEAR
  594.         ASSUME DS:NOTHING,ES:NOTHING
  595.         MOV    CX,DS:[SI]        ;get count of pages
  596. EMS_16_1_L1:    MOV    BX,2[SI]        ;get logical page
  597.         MOV    AX,4[SI]        ;get address of page to
  598.         MOV    DX,6[SI]        ;  restore
  599.         CALL    EMS_EXCH_PAG        ;Exchange current window page
  600.         ADD    SI,6            ;Point si to next page
  601.         LOOP    EMS_16_1_L1        ;No, loop back
  602.         XOR    AX,AX            ;Clear error code
  603. EMS_16_1_EXIT:    RET
  604. EMS_16_1    ENDP
  605. ;----------------------------------------------------------------------
  606. ;Function 16.2  Get partial mapping array size
  607. ;----------------------------------------------------------------------
  608. EMS_16_2    PROC    NEAR
  609.         ASSUME DS:NOTHING,ES:NOTHING
  610.         MOV    AX,BX            ;get nubmer of pages
  611.         MOV    AH,6            ;6 bytes per page
  612.         MUL    AH
  613.         ADD    AX,2            ;add room for count
  614.         XOR    AH,AH            ;zero return code
  615.         RET
  616. EMS_16_2    ENDP
  617. ;======================================================================
  618. ;Function 17.  Map Multiple Handle Pages
  619. ;======================================================================
  620. EMS_17        PROC    NEAR
  621.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  622.         MOV    ES,SS:[BP-8]        ;get pointer to map structure
  623.         CALL    EMS_17_INTERNAL
  624.         RET
  625. EMS_17        ENDP
  626. ;----------------------------------------------------------------------
  627. ;Function 17 (internal).  Used by jump and call routines to map pages.
  628. ;----------------------------------------------------------------------
  629. EMS_17_INTERNAL    PROC    NEAR
  630.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  631.         PUSH    BX
  632.         PUSH    DX
  633.         JC    EMS_17_EXIT        ;carry set, invalid handle
  634.         CMP    AL,1            ;no subfunction > 1.
  635.         JA    EMS_17_ERR1
  636.         CMP    CX,4            ;Make sure count < number of
  637.         JA    EMS_17_ERR2        ;  mappable pages.
  638.         MOV    CH,AL            ;save subfunction
  639. EMS_17_L1:    MOV    AX,ES:2[SI]        ;get physical page number/seg
  640.         OR    CH,CH
  641.         JE    EMS_17_S3        ;if seg address mapping,
  642.         CALL    EMS_SEG2LOG        ;  convert seg addr to number
  643.         JC    EMS_17_EXIT        ;check for error on conversion
  644.         MOV    AL,BL
  645. EMS_17_S3:    MOV    BX,ES:[SI]        ;get logical page number
  646.         CLC                ;handle valid
  647.         PUSH    CX            ;save count
  648.         CALL    EMS_05            ;map page
  649.         POP    CX            ;restore count
  650.         OR    AH,AH            ;check for error
  651.         JNE    EMS_17_EXIT
  652.         ADD    SI,4            ;Move pointers to next
  653.         DEC    CL            ;  mapping structure.
  654.         JNZ    EMS_17_L1
  655.         XOR    AX,AX            ;clear return code
  656. EMS_17_EXIT:    POP    DX
  657.         POP    BX
  658.         RET
  659. EMS_17_ERR1:    MOV    AH,8FH            ;invalid subfunction
  660.         JMP    SHORT EMS_17_EXIT
  661. EMS_17_ERR2:    MOV    AH,8BH            ;Number exceeds mappable pages
  662.         JMP    SHORT EMS_17_EXIT    ;  in the system
  663. EMS_17_INTERNAL    ENDP
  664. ;======================================================================
  665. ;Function 18.  Reallocate Pages
  666. ;======================================================================
  667. EMS_18        PROC    NEAR
  668.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  669.         PUSH    BX
  670.         PUSH    DX
  671.         JC    EMS_18_EXIT        ;carry set, invalid handle
  672.         MOV    DI,BX            ;save reallocation count
  673.         PUSH    BX
  674.         CALL    EMS_13            ;get current count
  675.         MOV    CX,BX
  676.         POP    BX            ;get back new count
  677.         SUB    BX,CX
  678.         JG    EMS_18_INCREASE
  679.         JL    EMS_18_REDUCE
  680.         XOR    AH,AH            ;clear return code
  681. EMS_18_EXIT:    POP    DX
  682.         POP    BX
  683.         RET
  684. EMS_18_INCREASE:
  685.         CALL    EMS_ASSIGN
  686.         JMP    SHORT EMS_18_EXIT
  687. EMS_18_REDUCE:    NEG    BX            ;turn into positive number
  688.         CALL    EMS_DEALLOC
  689.         JMP    SHORT EMS_18_EXIT
  690. EMS_18        ENDP
  691. ;======================================================================
  692. ;Function 19. Get/Set Handle Attribute (Not Supported)
  693. ;======================================================================
  694. EMS_19        PROC    NEAR
  695.         ASSUME CS:CODE,DS:CODE
  696.         CMP    AL,1
  697.         JE    EMS_19_1           ;Set handle attribute.
  698.         CMP    AL,2            ;For subfunctions 0 and 2,
  699.         JG    EMS_19_ERR1        ;  return volatile handle,
  700. EMS_19_GOOD_EXIT:
  701.         XOR    AX,AX                   ;  non-volatile not supp
  702. EMS_19_EXIT:    RET
  703. EMS_19_1:    CALL    EMS_CHECK_HDL        ;See if good handle
  704.         JC    EMS_19_ERR2
  705.         CMP    BL,1             ;See if legal attribute type
  706.         JG     EMS_19_ERR3          ;  or if non-volatile.
  707.         JL    EMS_19_GOOD_EXIT
  708.         MOV    AH,91H            ;function not supported
  709.         JMP    SHORT EMS_19_EXIT
  710. EMS_19_ERR1:    MOV    AH,8FH            ;subfunction invalid
  711.         JMP    SHORT EMS_19_EXIT
  712. EMS_19_ERR2:    MOV    AH,83H            ;invalid handle
  713.         JMP    SHORT EMS_19_EXIT
  714. EMS_19_ERR3:    MOV    AH,90H            ;attribute type not defined.
  715.         JMP    SHORT EMS_19_EXIT
  716. EMS_19        ENDP
  717. ;======================================================================
  718. ;Function 20. Get/Set Handle Name
  719. ;======================================================================
  720. EMS_20        PROC    NEAR
  721.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  722.         PUSH    BX
  723.         PUSH    DX
  724.         PUSH    DS
  725.         JC    EMS_20_EXIT        ;carry set, invalid handle
  726.         PUSH    AX            ;find spot for handle
  727.         MOV    BX,CS            ;get code segment
  728.         MOV    AX,DX            ;Compute offset by multipling
  729.         MOV    AH,9            ;  the handle number by the
  730.         MUL    AH            ;  size of each entry (9).
  731.         MOV    DX,AX
  732.         ADD    DX,HANDLE_ARRAY
  733.         INC    DX            ;point dx past the handle used
  734.         POP    AX            ;  flag.
  735.         OR    AL,AL            ;Check for get or set subfun.
  736.         JNE    EMS_20_S1
  737. ;Get Handle Name
  738.         MOV    SI,DX            ;load pointer to handle name
  739.         JMP    SHORT EMS_20_MOV
  740. ;Set Handle Name
  741. EMS_20_S1:    CMP    AL,1            ;Make sure that subfunction
  742.         JNE    EMS_20_ERR1             ;  = 1.
  743.         MOV    DS,SS:[BP-8]            ;Get original DS
  744.         ASSUME  DS:NOTHING
  745.         PUSH    SI
  746.         PUSH    DX
  747.         CALL    EMS_21_1        ;First, search for handle
  748.         POP    DX            ;  with this name. The
  749.         POP    SI            ;  return code must be a0h.
  750.         AND    AH,0FEH            ;  or a1h.
  751.         CMP    AH,0A0H
  752.         JNE    EMS_20_ERR2
  753.         MOV    DI,DX            ;Get back name pointer
  754.         PUSH    CS
  755.         POP    ES
  756.         ASSUME  ES:CODE
  757. EMS_20_MOV:    MOV    CX,8            ;copy name. move 8 bytes
  758.         REP    MOVSB
  759.         XOR    AX,AX            ;clear return code
  760. EMS_20_EXIT:    POP    DS
  761.         POP    DX
  762.         POP    BX
  763.         RET
  764. EMS_20_ERR1:    MOV    AH,8FH            ;Invalid subfunction
  765.         JMP    SHORT EMS_20_EXIT
  766. EMS_20_ERR2:    MOV    AH,0A1H            ;Handle already used
  767.         JMP    SHORT EMS_20_EXIT
  768. EMS_20        ENDP
  769. ;======================================================================
  770. ;Function 21. Get Handle directory
  771. ;======================================================================
  772. EMS_21_TBL    DW    OFFSET EMS_21_0    ;Jump table for subfunctions
  773.         DW    OFFSET EMS_21_1
  774.         DW    OFFSET EMS_21_2
  775. EMS_21        PROC    NEAR
  776.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  777.         PUSH    DS
  778.         MOV    DS,SS:[BP-8]        ;Get original DS
  779.         ASSUME  DS:NOTHING
  780.         CMP    AL,2            ;check subfunction < 3
  781.         JA    EMS_21_ERROR
  782.         XOR    AH,AH            ;clear top byte of subfunction
  783.         MOV    DI,AX            ;convert into jump address
  784.         SAL    DI,1
  785.         ADD    DI,OFFSET EMS_21_TBL
  786.         CALL    CS:[DI]
  787. EMS_21_EXIT:    POP    DS
  788.         RET
  789. EMS_21_ERROR:    MOV    AH,8FH            ;invalid subfunction
  790.         JMP    SHORT EMS_21_EXIT
  791. EMS_21        ENDP
  792. ;----------------------------------------------------------------------
  793. ;Function 21.0  Get Handle Directory
  794. ;----------------------------------------------------------------------
  795. EMS_21_0    PROC    NEAR
  796.         ASSUME  DS:NOTHING,ES:NOTHING
  797.         PUSH    DX
  798.         PUSH    CS
  799.         POP    DS
  800.         ASSUME  DS:CODE
  801.         MOV    SI,HANDLE_ARRAY
  802.         MOV    DI,SS:[BP-4]        ;Get original DI
  803.         XOR    AX,AX            ;Clear RC and hndl counter
  804.         MOV    DX,AX            ;Start with handle 0
  805. EMS_21_0_L1:    CMP    BYTE PTR [SI],0        ;Check flag to see if handle
  806.         JE    EMS_21_0_S1        ;  is used.
  807.         MOV    ES:[DI],DX        ;Store handle value
  808.         INC    SI            ;move SI past handle flag
  809.         ADD    DI,2            ;move DI past handle
  810.         MOV    CX,8            ;8 char per handle name
  811.         REP    MOVSB
  812.         INC    AL            ;add to handle count
  813.         JMP    SHORT EMS_21_0_S2
  814. EMS_21_0_S1:    ADD    SI,9            ;move to the next handle
  815. EMS_21_0_S2:    INC    DX            ;check next handle
  816.         CMP    DX,TOTAL_HANDLES    ;last handle?
  817.         JB    EMS_21_0_L1        ;no, loop back
  818.         POP    DX
  819.         RET
  820. EMS_21_0    ENDP
  821. ;----------------------------------------------------------------------
  822. ;Function 21.1  Search for Named Handle
  823. ;----------------------------------------------------------------------
  824. EMS_21_1    PROC    NEAR
  825.         ASSUME DS:NOTHING
  826.         PUSH    BX
  827.         PUSH    DS            ;copy segment of name
  828.         POP    ES
  829.         ASSUME ES:NOTHING
  830.         MOV    DI,SI
  831.         MOV    CX,8            ;Check for null string. If
  832.         XOR    AL,AL            ;  null, skip scan for dup
  833.         REPE    SCASB            ;  strings.
  834.         JE    EMS_21_1_ERR1
  835.         MOV    CX,CS:TOTAL_HANDLES    ;look at all handles
  836.         PUSH    CS            ;ES:DI -> handle array
  837.         POP    ES            ;DS:SI -> handle name
  838.         ASSUME  ES:CODE
  839.         MOV    BX,SI            ;bx holds handle name ptr
  840.         MOV    AX,CS:HANDLE_ARRAY    ;ax holds handle array ptr
  841.         INC    AX            ;move ax past handle flag
  842.         XOR    DX,DX            ;start handle count at 0
  843. EMS_21_1_L1:    MOV    DI,AX            ;Compare each of the handle
  844.         MOV    SI,BX            ;  names with the new handle
  845.         PUSH    CX
  846.         MOV    CX,8
  847.         REPE    CMPSB
  848.         POP    CX
  849.         JE    EMS_21_1_EXIT        ;If match found print err msg.
  850.         ADD    AX,9            ;move AX to next handle
  851.         INC    DX
  852.         LOOP    EMS_21_1_L1
  853.         MOV    AH,0A0H            ;handle not found
  854.         JMP    SHORT EMS_21_1_EXIT1
  855. EMS_21_1_EXIT:    XOR    AH,AH
  856. EMS_21_1_EXIT1:    POP    BX
  857.         RET
  858. EMS_21_1_ERR1:    MOV    AH,0A1H            ;null handle found
  859.         JMP    SHORT EMS_21_1_EXIT1
  860. EMS_21_1    ENDP
  861. ;----------------------------------------------------------------------
  862. ;Function 21.2  Get Total Handles
  863. ;----------------------------------------------------------------------
  864. EMS_21_2    PROC    NEAR
  865.         ASSUME    DS:NOTHING
  866.         MOV    BX,CS:TOTAL_HANDLES    ;Get number of allowed hdls
  867.         XOR    AX,AX           ;Clear return code.
  868.         RET
  869. EMS_21_2    ENDP
  870. ;======================================================================
  871. ;Function 22. Alter Page Map and Jump
  872. ;======================================================================
  873. EMS_22        PROC    NEAR
  874.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  875.         JC    EMS_22_EXIT        ;carry set, invalid handle
  876. ;Map new pages into window
  877.         MOV    DI,SI            ; ES:DI = pointer to map and
  878.         MOV    ES,SS:[BP-8]        ;  jump data
  879.         MOV     SI,ES:[DI]        ;Modify return address on
  880.         MOV    SS:[BP+2],SI        ;  the stack to the address
  881.         MOV     SI,ES:2[DI]        ;  in the jump structure.
  882.         MOV    SS:[BP+4],SI
  883.         MOV    SI,ES:5[DI]        ;Get pointer to mapping
  884.         MOV    ES,ES:7[DI]        ;   structure.
  885.         MOV    CL,ES:4[DI]        ;get mapping count
  886.         XOR    CH,CH
  887.         CALL    EMS_17_INTERNAL        ;alter page map
  888. EMS_22_EXIT:    RET
  889. EMS_22        ENDP
  890. ;======================================================================
  891. ;Function 23. Alter Page Map and Call
  892. ;======================================================================
  893. EMS_23        PROC    NEAR
  894.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  895.         JC    EMS_23_JMP_END          ;carry set, invalid handle
  896.         CMP    AL,2            ;Check for stack size function
  897.         JNE    EMS_23_S1
  898.         MOV    BX,28            ;Say we need 28 bytes
  899.         XOR    AH,AH
  900. EMS_23_JMP_END:    JMP    EMS_23_EXIT
  901. EMS_23_S1:    PUSH    AX            ;Save subfunction
  902. ;Map new pages into window
  903.         MOV    DI,SI            ;get pointer to map and
  904.         MOV    ES,SS:[BP-8]        ;  jump data
  905.         PUSH    ES            ;Save pointer to structure
  906.         PUSH    DI
  907.         XOR    CH,CH
  908.         MOV    CL,ES:[DI+4]        ;get mapping count
  909.         MOV    SI,ES:[DI+5]        ;get pointer to mapping
  910.         MOV    ES,ES:[DI+7]        ;   structure
  911.         PUSH    AX
  912.         CLC                ;indicate good handle
  913.         CALL    EMS_17_INTERNAL        ;alter page map
  914.         OR    AH,AH
  915.         POP    AX            ;Restore AX
  916.         JNE    EMS_23_EXIT
  917. ;Restore values in the registers and call.
  918.         MOV    AX,SS:[BP+6]        ;get flags
  919.         PUSH    AX
  920.         POPF                ;load flags
  921.         MOV    ES,SS:[BP-10]        ;restore ES
  922.         MOV    DS,SS:[BP-8]            ;Restore DS
  923.         MOV    SI,SS:[BP-6]        ;Restore SI
  924.         MOV    DI,SS:[BP-4]        ;Restore DI
  925.         MOV    DI,SS:[BP-2]        ;Restore CX
  926.         ASSUME    DS:NOTHING
  927.         PUSH    BP                      ;Save my base pointer
  928.         MOV    BP,SS:[BP]        ;Restore BP
  929.         MOV    AX,0000            ;Clear return code
  930.         CALL    DWORD PTR DS:[SI]    ;Call.
  931.         POP    AX            ;Get back pointer to stack
  932.         PUSH    BP            ;Save returned BP
  933.         MOV     BP,AX            ;Restore my base pointer
  934.         POP    AX            ;Get back returned BP
  935.         PUSHF                ;Save returned flags
  936.         MOV    [BP-10],ES
  937.         MOV    [BP-8],DS        ;Put reg values on stack
  938.         MOV    [BP-6],SI               ;  to be restored on return
  939.         MOV    [BP-4],DI
  940.         MOV    [BP-2],CX
  941.         POP    CX                 ;Get back returned flags
  942.         MOV    SS:[BP+6],CX
  943.         MOV    SS:[BP],AX        ;Save returned BP
  944.         PUSH    CS
  945.         POP    DS
  946.         ASSUME DS:CODE
  947. ;Map old pages into window
  948.         POP    DI            ;Get back pointer to structure
  949.         POP    ES
  950.         XOR    CH,CH
  951.         MOV    CL,ES:[DI+9]        ;get mapping count
  952.         MOV    SI,ES:[DI+10]        ;get pointer to mapping
  953.         MOV    ES,ES:[DI+12]        ;   structure
  954.         CLC                ;indicate good handle
  955.         POP    AX            ;Restore subfunction
  956.         CALL    EMS_17_INTERNAL        ;alter page map
  957. EMS_23_EXIT:    RET
  958. EMS_23        ENDP
  959. ;======================================================================
  960. ;Function 24.  Move/Exchange Memory Region
  961. ;======================================================================
  962. EMS_24_SUBFUN    EQU    [BP-1]            ;Saved subfunction
  963. EMS_24_DIR    EQU    [BP-2]            ;Direction flag for move
  964. EMS_24_COUNT    EQU    [BP-6]            ;Amount of memory to move
  965. EMS_24_SRC_PTR    EQU    [BP-10]            ;Source move pointer
  966. EMS_24_DEST_PTR    EQU    [BP-14]            ;Destination move pointer
  967. EMS_24_RET_CODE    EQU    [BP-15]            ;RC for non-fatal error codes
  968. EMS_24        PROC    NEAR
  969.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  970.         PUSH    BX            ;Save registers
  971.         PUSH    DX
  972.         MOV    ES,SS:[BP-8]        ;Get DS off original stack
  973.         PUSH    ES            ;Push for local addressability
  974.         PUSH    SI
  975.         PUSH    BP
  976.         MOV    BP,SP            ;Set up pointer to local data
  977.         SUB    SP,18            ;Make room on stack for data
  978.         MOV     EMS_24_SUBFUN,AL        ;Save subfunction
  979.         MOV    BYTE PTR EMS_24_RET_CODE,0
  980.         MOV    AX,ES:[SI]        ;Get count from move struc
  981.         MOV    DX,ES:[SI+2]
  982.         CMP    DX,10H            ;see if region size > 1M
  983.         JB     EMS_24_S0
  984.         MOV    AH,96H            ;region > 1M byte
  985.         JMP    EMS_24_EXIT
  986. EMS_24_S0:    MOV    WORD PTR [EMS_24_COUNT],AX    ;Save count. Compute
  987.         MOV    WORD PTR [EMS_24_COUNT+2],DX    ;  the number of
  988.         MOV    CX,16384                ;  16K pages needed.
  989.         DIV    CX
  990.         MOV    CH,AL            ;Save number of pages
  991.         MOV    CL,DL            ;save remainder
  992. ;Verify handles have the pages assigned. (If Expanded memory.)
  993.         ADD    SI,4            ;move pointer to source descr
  994.         MOV    DI,-10            ;Pointer to src local store
  995.         CALL    EMS_CHECK_MOV
  996.         JC    EMS_24_JMP_EXIT
  997.         PUSH    AX            ;Save source end address
  998.         PUSH    DX
  999.         ADD    SI,7                    ;Point to destination block
  1000.         MOV    DI,-14            ;Pointer to dest local store
  1001.         CALL    EMS_CHECK_MOV
  1002.         POP    DI                      ;Recover source end address
  1003.         POP    BX
  1004.         JNC    EMS_24_S01              ;If error flag set, exit
  1005. EMS_24_JMP_EXIT:
  1006.         JMP    EMS_24_EXIT
  1007. EMS_24_S01:    MOV    BYTE PTR EMS_24_DIR,0    ;Set direction flag bottom up
  1008. ;Check and adjust for overlap if necessary. If exchange, don't allow overlap.
  1009.         MOV    CL,BYTE PTR ES:[SI]      ;Get destination memory type
  1010.         ADD    CL,BYTE PTR ES:[SI-7]      ;Compare to source memory type
  1011.         CMP    CL,1            ;0 = both conv, 1 = diff types,
  1012.         JE    EMS_24_MOVEDATA        ;  2 = both expanded.
  1013.         JB    EMS_24_S2        ;0, check conv overlap.
  1014.         MOV    CX,ES:[SI+1]        ;Get dest handle
  1015.         CMP    CX,ES:[SI-6]        ;Compare to source handle
  1016.         JNE    EMS_24_MOVEDATA        ;Not the same, no overlap
  1017.         MOV    CX,ES:[SI-2]        ;Get source starting page
  1018.         CMP    CX,ES:[SI+5]        ;Compare dest starting page
  1019.         JB    EMS_24_S1          ;If source starts first,
  1020.         JA    EMS_24_S02              ;  bottom up move.
  1021.         MOV    CX,ES:[SI-4]            ;Get source starting offset
  1022.         CMP    CX,ES:[SI+3]            ;Get source starting offset
  1023.         JB    EMS_24_S1        ;Source lower, bottom up move
  1024. EMS_24_S02:    MOV     BX,AX                   ;Copy from top down.
  1025.         MOV     DI,DX            ;Put end addr of Dest in DI,BX
  1026.         SUB    SI,7            ;Point to source descriptor
  1027.         MOV    BYTE PTR EMS_24_DIR,1    ;Set direction top down
  1028. EMS_24_S1:    CMP    DI,ES:[SI+5]        ;Compare end with start addr
  1029.         JB    EMS_24_MOVEDATA        ;No overlap
  1030.         JA    EMS_24_OVERLAP        ;Overlap
  1031.         CMP    BX,ES:[SI+3]        ;Same pages, check offsets
  1032.         JB    EMS_24_MOVEDATA        ;If less, no overlap
  1033.         JMP    SHORT EMS_24_OVERLAP
  1034. ;Check for overlap of conventional memory regions.
  1035. EMS_24_S2:    CMP    DX,DI            ;Compare high word
  1036.         JB    EMS_24_S3        ;dest higher, top down
  1037.         JA    EMS_24_S21              ;Less, bottom up.
  1038.         CMP    AX,BX            ;Compare low word of address
  1039.         JB     EMS_24_S3        ;Jmp if dest addr higher
  1040. EMS_24_S21:    MOV    SI,-14            ;Point to dest descriptor
  1041.         CALL    EMS_24_ADR_CNV
  1042.         XCHG    DI,DX            ;Exchange starting addresses
  1043.         XCHG    BX,AX
  1044.         MOV    SI,-10            ;Point to source descriptor
  1045.         CALL    EMS_24_ADR_CNV
  1046.         MOV    BYTE PTR EMS_24_DIR,1    ;Set direction flag top down
  1047. EMS_24_S3:    SUB    BX,WORD PTR [EMS_24_COUNT]    ;Generate start addr
  1048.         SBB    DI,WORD PTR [EMS_24_COUNT+2]
  1049.         CMP    DX,DI                   ;Compare starting addr with
  1050.         JB    EMS_24_MOVEDATA        ;  end of other block
  1051.         CMP    AX,BX
  1052.         JBE    EMS_24_MOVEDATA
  1053. EMS_24_OVERLAP:    MOV    BYTE PTR EMS_24_RET_CODE,92H    ;Indicate overlap
  1054.         CMP    BYTE PTR EMS_24_SUBFUN,0    ;If exch. don't allow
  1055.         JE    EMS_24_MOVEDATA                 ;  overlap.
  1056.         MOV    AH,97H                ;Error, no overlap
  1057.         JMP    EMS_24_EXIT            ;  on exchange.
  1058. ;Move/Exchange the data
  1059. EMS_24_MOVEDATA:
  1060.         MOV    BX,MAP_ARRAY_PTR    ;Save context of pages 0 & 1
  1061.         PUSH    [BX+8]                  ;Save address for page 1
  1062.         PUSH    [BX+6]
  1063.         PUSH    [BX+4]            ;Save address for page 0
  1064.         PUSH    [BX+2]
  1065.         STD
  1066.         CMP    BYTE PTR EMS_24_DIR,0   ;If moving from top to bottom
  1067.         JNE    EMS_24_MOVE0            ;  set direction flag for move
  1068.         CLD
  1069.         MOV    AX,ES:[SI-4]        ;If move from bottom to top,
  1070.         MOV    DX,ES:[SI-2]                    ;  initialize the
  1071.         MOV    WORD PTR [EMS_24_SRC_PTR],AX    ;  pointers back to
  1072.         MOV    WORD PTR [EMS_24_SRC_PTR+2],DX  ;  the starting
  1073.         MOV    AX,ES:[SI+3]                    ;  addresses.
  1074.         MOV    DX,ES:[SI+5]
  1075.         MOV    WORD PTR [EMS_24_DEST_PTR],AX
  1076.         MOV    WORD PTR [EMS_24_DEST_PTR+2],DX
  1077. EMS_24_MOVE0:    XOR    CX,CX            ;Clear last move count
  1078. EMS_24_MOVELOOP:
  1079.         MOV    ES,[BP+4]        ;Restore move structure
  1080.         MOV    BX,[BP+2]        ;  pointer to ES:BX
  1081.         MOV    DX,ES            ;Save ES
  1082.         MOV     AX,CX            ;Save last count
  1083.         ADD    BX,4                    ;Point to source descriptor
  1084.         XOR    SI,SI            ;Indicate source
  1085.         CALL    EMS_24_MOV_SET
  1086.         PUSH    ES              ;Save source pointer
  1087.         PUSH    DI
  1088.         XCHG    CX,AX            ;save count, restore last cnt
  1089.         MOV    ES,DX            ;Restore ES
  1090.         ADD    BX,7            ;Point to dest mem descriptor
  1091.         MOV    SI,1
  1092.         CALL    EMS_24_MOV_SET         ;Map extended mem if needed
  1093.                 POP     SI            ;Get back source pointer
  1094.         POP    BX            ;Save segment in BX
  1095.         CMP    AX,CX                     ;Get lower count
  1096.         JA    EMS_24_MOVE1
  1097.         MOV    CX,AX
  1098. EMS_24_MOVE1:    MOV    AX,WORD PTR [EMS_24_COUNT]      ;Get move count
  1099.         MOV    DX,WORD PTR [EMS_24_COUNT+2]
  1100.         OR    DX,DX                           ;See if at end of
  1101.         JNE    EMS_24_MOVE2                    ;  count. If so,
  1102.         CMP    AX,CX                           ;  copy only to end
  1103.         JA    EMS_24_MOVE2                    ;  of count.
  1104.         MOV    CX,AX
  1105. EMS_24_MOVE2:    SUB    AX,CX            ;Subtract from count
  1106.         SBB    DX,0
  1107.         PUSH    CX
  1108.         PUSH    AX                      ;Save count
  1109.         PUSH    DX
  1110.         CMP    BYTE PTR EMS_24_SUBFUN,1    ;See if move or exch
  1111.         MOV    DS,BX            ;Time to set DS
  1112.         ASSUME    DS:NOTHING
  1113.         JE    EMS_24_EXCH
  1114.         REP    MOVSB            ;Move that data
  1115.                 JMP    SHORT EMS_24_MOVE3
  1116. EMS_24_EXCH:    MOV    BL,ES:[DI]        ;Get dest byte
  1117.         MOVSB
  1118.         CMP    BYTE PTR EMS_24_DIR,0    ;Check direction flag to
  1119.         JNE    EMS_24_EXCH1            ;  make sure of pointers
  1120.         MOV     DS:[SI-1],BL        ;Move dest byte to source
  1121.         JMP    SHORT EMS_24_EXCH2
  1122. EMS_24_EXCH1:    MOV     DS:[SI+1],BL        ;Move dest byte to source
  1123. EMS_24_EXCH2:    LOOP    EMS_24_EXCH             ;Loop until block exchanged.
  1124. EMS_24_MOVE3:    PUSH    CS                      ;Restore DS altered by move
  1125.         POP    DS
  1126.         ASSUME    DS:CODE
  1127.         POP    DX            ;Get back count
  1128.         POP    AX
  1129.         POP    CX
  1130.         MOV    WORD PTR [EMS_24_COUNT],AX    ;Restore count
  1131.         MOV    WORD PTR [EMS_24_COUNT+2],DX
  1132.         OR    DX,DX
  1133.         JNE    EMS_24_MOVE4            ;See if count has expired.
  1134.         OR    AX,AX
  1135.         JLE    EMS_24_LOOP_DONE
  1136. EMS_24_MOVE4:    JMP    EMS_24_MOVELOOP
  1137. EMS_24_LOOP_DONE:                ;Restore pages 0 and 1.
  1138.         XOR    BX,BX            ;set physical page = 0
  1139.         POP    AX              ;get address of page to
  1140.         POP    DX              ;  restore
  1141.         CALL    EMS_EXCH_PAG        ;Exchange current window page
  1142.         MOV    BX,1             ;set physical page = 1
  1143.         POP    AX              ;get address of page to
  1144.         POP    DX              ;  restore
  1145.         CALL    EMS_EXCH_PAG        ;Exchange current window page
  1146.         MOV    AH,BYTE PTR EMS_24_RET_CODE    ;Get return code
  1147. EMS_24_EXIT:    ADD    SP,18            ;Deallocate local storage
  1148.         POP    BP
  1149.         POP    SI
  1150.         POP    ES
  1151.         POP    DX
  1152.         POP    BX
  1153.         RET
  1154. EMS_24        ENDP
  1155. ;----------------------------------------------------------------------
  1156. ;Convert address to segment offset form
  1157. ;Entry: dx ax - address
  1158. ;          si - pointer to local memory descriptor
  1159. ;----------------------------------------------------------------------
  1160. EMS_24_ADR_CNV    PROC    NEAR
  1161.         PUSH    AX
  1162.         PUSH    DX
  1163.         MOV    CX,16384        ;Convert address to seg:offset
  1164.         DIV    CX
  1165.         MOV    WORD PTR [BP+SI],DX    ;Save offset
  1166.         MOV    CL,10
  1167.         SAL    AX,CL
  1168.         MOV    WORD PTR [BP+SI+2],AX   ;Save segment
  1169.         POP    DX
  1170.         POP    AX
  1171.         RET
  1172. EMS_24_ADR_CNV    ENDP
  1173. ;----------------------------------------------------------------------
  1174. ;Setup ems page for move.
  1175. ;Entry:    al - 0 = source page, 1 = destination page.
  1176. ;       es:bx - pointer to external memory descriptor
  1177. ;          cx - Count used on last move
  1178. ;Exit:  ES:DI - pointer to data to move
  1179. ;          cx - max count before crossing boundry.
  1180. ;----------------------------------------------------------------------
  1181. EMS_24_MOV_SET    PROC    NEAR
  1182.         ASSUME    DS:CODE
  1183.         PUSH    AX
  1184.         PUSH    BX
  1185.         PUSH    DX
  1186.         MOV    DX,SI
  1187.         MOV    SI,-10                  ;Use SI as offset to src_ptr
  1188.         OR    DX,DX
  1189.         JE    EMS_24_MOV_SET_S0
  1190.         SUB    SI,4            ;Point SI to dest_ptr
  1191. EMS_24_MOV_SET_S0:
  1192.         MOV    DH,BYTE PTR ES:[BX]    ;Get memory type
  1193.         MOV    AX,16383        ;Load constants for EMS mem
  1194.         MOV    DI,1
  1195.         OR     DH,DH                 ;Check type of number
  1196.         JNE    EMS_24_MOV_SET_S1    ;1 = EMS memory
  1197.         MOV    DI,1024                 ;Load constants for
  1198.                             ;  conventional memory.
  1199. EMS_24_MOV_SET_S1:
  1200.         CMP    BYTE PTR EMS_24_DIR,0    ;If bottom up move, skip
  1201.         JE    EMS_24_MOV_SET_S3
  1202. ;Top down.
  1203.         SUB    WORD PTR [BP+SI],CX    ;Sub last move from offset
  1204.         JAE    EMS_24_MOV_SET_S2    ;See if end of page
  1205.         MOV    WORD PTR [BP+SI],AX       ;Start at top of next page
  1206.         SUB    WORD PTR [BP+SI+2],DI    ;Point to next page
  1207. EMS_24_MOV_SET_S2:
  1208.         MOV    CX,WORD PTR [BP+SI]    ;Get offset for count
  1209.         INC    CX
  1210.         JMP    EMS_24_MOV_SET_S5
  1211. ;Bottom up
  1212. EMS_24_MOV_SET_S3:
  1213.         ADD    WORD PTR [BP+SI],CX    ;Add last move to offset
  1214.         CMP    WORD PTR [BP+SI],AX       ;See if end of page
  1215.         JBE    EMS_24_MOV_SET_S4
  1216. EMS_24_MOV_SET_S31:
  1217.         MOV    WORD PTR [BP+SI],0     ;Start at bottom of page
  1218.         ADD    WORD PTR [BP+SI+2],DI     ;Point to next page
  1219. EMS_24_MOV_SET_S4:
  1220.         MOV    CX,AX                   ;Compute count to end of page
  1221.         SUB    CX,WORD PTR [BP+SI]
  1222.          INC    CX
  1223. EMS_24_MOV_SET_S5:
  1224.         OR     DH,DH                  ;Check type of number
  1225.         JE    EMS_24_MOV_SET_CONV1    ;If conventional, don't map
  1226.         PUSH    CX            ;Save new count
  1227.         PUSH    DX
  1228.         MOV    AL,DL            ;Pass proper phyical page
  1229.         MOV    DX,WORD PTR ES:[BX+1]    ;Get handle
  1230.         MOV    BX,WORD PTR [BP+SI+2]    ;Put page in proper register
  1231.         PUSHF
  1232.         CLD                ;Set assumed direction flag
  1233.         CLC                ;Set handle good flag
  1234.         CALL    EMS_05            ;Map page
  1235.         POPF
  1236.         POP    DX
  1237.         POP    CX            ;Get count back
  1238.         MOV    AX,WINDOW_SEG        ;Get window segment
  1239.         OR    DL,DL            ;See if source or dest
  1240.         JE    EMS_24_MOV_SET_S6       ;If destination, point to
  1241.         ADD    AX,1024                 ;  2nd page. 1024 paragraphs
  1242. EMS_24_MOV_SET_S6:
  1243.         MOV    ES,AX            ;Set pointer to data
  1244. EMS_24_MOV_SET_EXIT:
  1245.         MOV    DI,WORD PTR [BP+SI]    ;Load offset
  1246.         POP    DX
  1247.         POP    BX
  1248.         POP    AX
  1249.         RET
  1250. EMS_24_MOV_SET_CONV1:
  1251.         MOV    DI,WORD PTR [BP+SI+2]
  1252.         MOV    ES,DI
  1253.         JMP    SHORT EMS_24_MOV_SET_EXIT
  1254. EMS_24_MOV_SET    ENDP
  1255. ;----------------------------------------------------------------------
  1256. ;Check parameters for move or exchange
  1257. ;Entry: es:si - pointer to memory descriptor
  1258. ;       bp+di - pointer to local store descriptor
  1259. ;          ch - number of extended pages needed
  1260. ;          cl - number of bytes into last extended page
  1261. ;Exit:  dx,ax - ending address if conventional
  1262. ;          ax - ending page if expanded
  1263. ;          dx - ending offset if expanded
  1264. ;----------------------------------------------------------------------
  1265. EMS_CHECK_MOV     PROC    NEAR
  1266.         ASSUME  DS:CODE,ES:NOTHING
  1267.         PUSH    BX
  1268.         PUSH    CX
  1269.         PUSH    DI
  1270.         XOR    AX,AX
  1271.         MOV    AL,CH            ;Get number of pages needed
  1272.         MOV    DI,AX            ;Save number of pages in DI
  1273.         XOR    CH,CH
  1274.         MOV    AX,ES:[SI+5]        ;Get segment/page
  1275.         MOV    BX,ES:[SI+3]        ;get offset
  1276.         MOV    DL,ES:[SI]        ;Get memory type
  1277.         OR    DL,DL            ;See if EMS or low memory
  1278.         JE     EMS_CHECK_MOV_CONV    ;jump if low memory
  1279.           CMP    DL,1            ;If not low mem make sure
  1280.         JE     EMS_CHECK_MOV_S1        ;  EMS memory.
  1281.         MOV    AH,98H            ;Invalid memory type
  1282.         JMP    EMS_CHECK_MOV_SET_ERR
  1283. EMS_CHECK_MOV_S1:
  1284.         CMP    BX,3FFFH        ;Check for offset < 16K
  1285.         JA    EMS_CHECK_MOV_ERR1
  1286. ;See if the handle owns enough pages to hold the region.
  1287.         MOV    DX,ES:[SI+1]        ;Get handle
  1288.         PUSH    CX
  1289.         CALL    EMS_CHECK_HDL       ;Verify handle.
  1290.         CALL    EMS_13            ;Get number of pages owned
  1291.         POP    CX                      ;  by handle
  1292.         OR    AH,AH            ;If error, set carry and
  1293.         JNE    EMS_CHECK_MOV_SET_ERR    ;  return.
  1294.         MOV    DX,BX            ;save number of pages
  1295.         MOV    BX,ES:[SI+5]        ;Get logical page number
  1296.         MOV    AX,DI            ;Copy number of pages needed
  1297.         ADD    AX,BX            ;Add starting page.
  1298.         ADD    CX,ES:[SI+3]        ;Add start offset to remainder
  1299.         DEC    CX                      ;  of the num of pages needed.
  1300.         CMP    CX,16384
  1301.         JL    EMS_CHECK_MOV_S4    ;If rem+offset > 16K add a
  1302.         INC    AX            ;  page to the num needed.
  1303.         SUB    CX,16384
  1304. EMS_CHECK_MOV_S4:
  1305.         CMP    AX,DX            ;Compare to total number of
  1306.         JG    EMS_CHECK_MOV_ERR3    ;  pages.
  1307.         MOV    DX,CX            ;Copy ending offset
  1308.         XCHG    AX,DX            ;Exchange offset and segment
  1309. EMS_CHECK_MOV_EXIT:
  1310.         CLC                ;Clear error flag
  1311. EMS_CHECK_MOV_EXIT1:
  1312.         POP    DI                      ;Restore registers
  1313.         MOV    [BP+DI],AX        ;Save offset
  1314.         MOV    [BP+DI+2],DX        ;Save segnent/page
  1315.         POP    CX
  1316.         POP    BX
  1317.         RET
  1318. EMS_CHECK_MOV_CONV:
  1319.         MOV    CX,16            ;convert segment into address
  1320.         MUL    CX
  1321.         ADD    AX,BX            ;Add offset
  1322.         ADC    DX,0
  1323.         ADD    AX,WORD PTR [EMS_24_COUNT]    ;Add len to start addr
  1324.         ADC    DX,WORD PTR [EMS_24_COUNT+2]
  1325.         SUB    AX,1            ;Decriment count
  1326.         SBB    DX,0
  1327.         JMP    SHORT EMS_CHECK_MOV_EXIT
  1328. EMS_CHECK_MOV_ERR1:
  1329.         MOV    AH,95H            ;offset too large
  1330. EMS_CHECK_MOV_SET_ERR:
  1331.         STC                         ;Indicate error
  1332.         JMP    SHORT EMS_CHECK_MOV_EXIT1
  1333. EMS_CHECK_MOV_ERR3:
  1334.         MOV    AH,93H            ;Not enough pages
  1335.         JMP    SHORT EMS_CHECK_MOV_SET_ERR
  1336. EMS_CHECK_MOV ENDP
  1337. ;======================================================================
  1338. ;Function 25. Get Mappable Physical Address Array
  1339. ;======================================================================
  1340. EMS_25        PROC    NEAR
  1341.         ASSUME  CS:CODE,DS:CODE,ES:NOTHING
  1342.         OR    AL,AL            ;check subfunction
  1343.         JE    EMS_25_S1
  1344.         CMP    AL,1            ;assure subfunction 0 or 1.
  1345.         JNE    EMS_25_ERR1
  1346.         MOV    WORD PTR SS:[BP-2],4    ;replace saved cx with 4
  1347.         JMP    SHORT EMS_25_EXIT
  1348. EMS_25_S1:    MOV    AX,WINDOW_SEG
  1349.         XOR    CX,CX
  1350. EMS_25_L1:    MOV    ES:[DI],AX        ;write segment
  1351.         MOV    ES:2[DI],CX        ;write segment number
  1352.         ADD    AX,1024         ;Point to next segment
  1353.         ADD    DI,4
  1354.         INC    CX                      ;Indicate next page
  1355.         CMP    CX,3
  1356.         JLE    EMS_25_L1
  1357.         INC    CX            ;number is 1 based not 0 based
  1358. EMS_25_EXIT:    XOR    AX,AX            ;clear return code
  1359. EMS_25_EXIT1:    RET
  1360. EMS_25_ERR1:    MOV    AH,8FH            ;Unknown subfunction
  1361.         JMP    SHORT EMS_25_EXIT1
  1362. EMS_25        ENDP
  1363. ;======================================================================
  1364. ;Function 26.  Get Expanded Memory Hardware Information
  1365. ;======================================================================
  1366. EMS_26        PROC    NEAR
  1367.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  1368.         CMP    OS_ENABLED,1        ;Are OS funcctions enabled?
  1369.         JNE    EMS_26_ERR1             ;No, exit
  1370.         CMP    AL,1                    ;Subfunction 1, get page cnt
  1371.         JB    EMS_26_0         ;Jmp to subfunction 0
  1372.         JA    EMS_26_ERR2        ;If > 1, invalid subfunction.
  1373. EMS_26_1:    CALL    EMS_03            ;Since raw page = normal page,
  1374.         JMP    SHORT EMS_26_EXIT       ;  get normal page count.
  1375. EMS_26_0:    XOR    CX,CX
  1376.         MOV    WORD PTR ES:[DI],1024   ;16K pages (1024 paragraphs)
  1377.         MOV    ES:2[DI],CX        ;No alternate register sets
  1378.         CALL    EMS_15_3        ;Get context area size
  1379.         MOV    ES:4[DI],AX
  1380.         MOV    ES:6[DI],CX        ;No DMA channels
  1381.         MOV    ES:8[DI],CX        ;DMA channel operation
  1382.         XOR    AX,AX            ;clear return code
  1383. EMS_26_EXIT:    RET
  1384. EMS_26_ERR1:    MOV    AH,0A4H            ;operating system denied
  1385.         JMP    SHORT EMS_26_EXIT    ;  access.
  1386. EMS_26_ERR2:    MOV    AH,8FH            ;Invalid subfunction
  1387.         JMP    SHORT EMS_26_EXIT
  1388. EMS_26        ENDP
  1389. ;======================================================================
  1390. ;Function 27.  Get handle and allocate pages
  1391. ;======================================================================
  1392. EMS_27        PROC    NEAR
  1393.         ASSUME DS:CODE,ES:NOTHING
  1394.         PUSH    BX            ;Save register
  1395.         CMP    BX,TOTAL_PAGES        ;Make sure request is not out
  1396.         JLE    EMS_27_S1        ;  of range.
  1397.         MOV    AH,87H            ;Not enough pages in system
  1398.         JMP    SHORT EMS_27_EXIT
  1399. EMS_27_S1:    PUSH    BX            ;save num. of pages to alloc
  1400.         XOR    DX,DX            ;search for handle =-1 (unaloc)
  1401.         DEC    DX
  1402.         CLC
  1403.         CALL    EMS_13            ;get unallocated page count.
  1404.         POP    CX
  1405.         CMP    BX,CX            ;check for enough free pages
  1406.         JL    EMS_27_ERR1
  1407.         MOV    DI,HANDLE_ARRAY        ;Assign handle
  1408.         XOR    AX,AX            ;search for free handles
  1409.         MOV    DX,AX            ;dx=0 at start of hndl search
  1410. EMS_27_L1:    CMP    AL,[DI]            ;if handle id = 0 then that
  1411.         JE    EMS_27_S2        ;  hndl has not been allocated.
  1412.         ADD    DI,9            ;Move di to point to next id.
  1413.         INC    DX
  1414.         CMP    DX,TOTAL_HANDLES    ;have we searched all handles?
  1415.         JB    EMS_27_L1
  1416.         MOV    AH,85H            ;no free handles
  1417.         JMP    SHORT EMS_27_EXIT
  1418. EMS_27_S2:    DEC    BYTE PTR [DI]        ;indicate that handle is used
  1419.         MOV    BX,CX
  1420.         CALL    EMS_ASSIGN        ;alloc pages, dx = new handle
  1421. EMS_27_EXIT:    POP    BX               ;Restore register
  1422.         RET
  1423. EMS_27_ERR1:    MOV    AH,88H
  1424.         JMP    SHORT EMS_27_EXIT
  1425. EMS_27        ENDP
  1426. ;======================================================================
  1427. ;Function 28. Alternate Map Register Set
  1428. ;======================================================================
  1429. EMS_28_TBL    DW    OFFSET EMS_28_0    ;Jump table for subfunctions
  1430.         DW    OFFSET EMS_28_1
  1431.         DW    OFFSET EMS_28_2
  1432.         DW    OFFSET EMS_28_3
  1433.         DW    OFFSET EMS_28_4
  1434.         DW    OFFSET EMS_28_3
  1435.         DW    OFFSET EMS_28_6
  1436. EMS_28        PROC    NEAR
  1437.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  1438.         CMP    OS_ENABLED,1        ;See if function enabled
  1439.         JNE    EMS_28_ERR1
  1440.         CMP    AL,8            ;check al for a number not 0-8
  1441.         JA    EMS_28_ERR2
  1442.         CMP    AL,6            ;check al for function 4-8.
  1443.         JLE    EMS_28_S1        ;If >5 point to unsupported
  1444.         MOV    AL,6            ;  routine.
  1445. EMS_28_S1:    XOR    AH,AH            ;clear top byte of subfunction
  1446.         MOV    DI,AX            ;convert into jump address
  1447.         SAL    DI,1
  1448.         ADD    DI,OFFSET EMS_28_TBL
  1449.         XOR    AX,AX            ;clear return code before call
  1450.         CALL    CS:[DI]
  1451. EMS_28_EXIT:    RET
  1452. EMS_28_ERR1:    MOV    AH,0A4H            ;operating system denied
  1453.         JMP    SHORT EMS_28_EXIT    ;  access.
  1454. EMS_28_ERR2:    MOV    AH,8FH            ;invalid subfunction
  1455.         JMP    SHORT EMS_28_EXIT
  1456. EMS_28        ENDP
  1457. ;----------------------------------------------------------------------
  1458. ;Function 28.0  Get Alternate Map Register Set
  1459. ;----------------------------------------------------------------------
  1460. EMS_28_0    PROC    NEAR
  1461.         PUSH    DX
  1462.         MOV    ES,ALT_MAP_PTRS        ;Get pointer
  1463.         MOV    DI,ALT_MAP_PTRO
  1464.         MOV    SS:[BP-4],DI        ;save values for exit
  1465.         MOV    SS:[BP-10],ES
  1466.         OR    DI,DI            ;See if it is zero
  1467.         JNE    EMS_28_0_S1
  1468.         MOV    CX,ES            ;If so, exit without saving
  1469.         OR    CX,CX            ;  page map array.
  1470.         XOR    AX,AX            ;Clear return code
  1471.         JE    EMS_28_0_EXIT
  1472. EMS_28_0_S1:    PUSH    DI            ;save original pointer
  1473.         CALL    EMS_15_0        ;copy page map
  1474.         POP    DI            ;The return code will be
  1475. EMS_28_0_EXIT:    XOR    BL,BL                   ;  set by Function 15.0
  1476.         POP    DX                      ;Indicate non-support for
  1477.         RET                             ;  alternate mapping regs.
  1478. EMS_28_0    ENDP
  1479. ;----------------------------------------------------------------------
  1480. ;Function 28.1  Set Alternate Map Register Set
  1481. ;----------------------------------------------------------------------
  1482. EMS_28_1    PROC    NEAR
  1483.         PUSH    BX
  1484.         PUSH    DX
  1485.         OR    BL,BL            ;check bl = 0
  1486.         JNE    EMS_28_1_ERR
  1487.         MOV    DI,[BP-4]        ;Restore DI
  1488.         MOV    ALT_MAP_PTRS,ES        ;Save mapping pointer
  1489.         MOV    ALT_MAP_PTRO,DI
  1490.         OR    DI,DI            ;See if it is zero
  1491.         JNE    EMS_28_1_S1
  1492.         MOV    CX,ES            ;If so, exit without restoring
  1493.         OR    CX,CX            ;  page map array.
  1494.         JE    EMS_28_1_EXIT
  1495. EMS_28_1_S1:    PUSH    DS
  1496.         MOV    SI,ES            ;Put pointer into ds:si for
  1497.         MOV    DS,SI            ;  function 15.1 call.
  1498.         ASSUME DS:NOTHING
  1499.         MOV    SI,DI           ;DS:SI = ES:DI
  1500.         CALL    EMS_15_1        ;Restore page map
  1501.         POP    DS
  1502.         ASSUME DS:CODE
  1503. EMS_28_1_EXIT:    POP    DX
  1504.         POP    BX
  1505.         RET
  1506. EMS_28_1_ERR:    MOV    AH,9CH            ;Alternate map register
  1507.         JMP    SHORT EMS_28_EXIT    ;  sets not supported.
  1508. EMS_28_1    ENDP
  1509. ;----------------------------------------------------------------------
  1510. ;Function 28.2  Get Alternate Map Save Array Size
  1511. ;----------------------------------------------------------------------
  1512. EMS_28_2    PROC    NEAR
  1513.         CALL    EMS_15_3        ;Get save array size.
  1514.         MOV    DX,AX
  1515.         RET
  1516. EMS_28_2    ENDP
  1517. ;----------------------------------------------------------------------
  1518. ;Function 28.3 and 28.5  Deallocate Map Register Set
  1519. ;----------------------------------------------------------------------
  1520. EMS_28_3    PROC    NEAR
  1521.         XOR    BL,BL            ;set bl = 0
  1522.         XOR    AX,AX
  1523.         RET
  1524. EMS_28_3    ENDP
  1525. ;----------------------------------------------------------------------
  1526. ;Function 28.4  Deallocate Alternate Map Register Set
  1527. ;----------------------------------------------------------------------
  1528. EMS_28_4    PROC    NEAR
  1529.         OR    BL,BL            ;See if zero page indicated
  1530.         JNE    EMS_28_4_ERR1        ;  if not, error
  1531.         XOR    AX,AX            ;Clear return code.
  1532.         MOV    ALT_MAP_PTRS,AX        ;Clear mapping pointer
  1533.         MOV    ALT_MAP_PTRO,AX
  1534. EMS_28_4_EXIT:    RET
  1535. EMS_28_4_ERR1:    MOV    AH,9CH            ;Alt register sets not
  1536.         JMP    SHORT EMS_28_4_EXIT    ;  supported
  1537. EMS_28_4    ENDP
  1538. ;----------------------------------------------------------------------
  1539. ;Function 28.6-28.8  Unsupported Subfunctions
  1540. ;----------------------------------------------------------------------
  1541. EMS_28_6    PROC    NEAR
  1542.         OR    BL,BL            ;see if zero page indicated
  1543.         JNE    EMS_28_6_ERR1        ;if not, error
  1544.         XOR    AX,AX            ;clear return code.
  1545. EMS_28_6_EXIT:    RET
  1546. EMS_28_6_ERR1:    MOV    AH,9CH            ;Alt register sets not
  1547.         JMP    SHORT EMS_28_6_EXIT    ;  supported
  1548. EMS_28_6    ENDP
  1549. ;======================================================================
  1550. ;Function 30.  OS/E Functions
  1551. ;======================================================================
  1552. EMS_30        PROC    NEAR
  1553.         PUSH    DX
  1554.         CMP    OS_PASS_LOW,0
  1555.         JNE    EMS_30_S1
  1556.         CMP    OS_PASS_HIGH,0
  1557.         JE    EMS_30_S2        ;first call, create password.
  1558. EMS_30_S1:    CMP    OS_PASS_LOW,BX        ;Check password
  1559.         JNE    EMS_30_ERR1
  1560.         CMP    OS_PASS_HIGH,CX
  1561.         JNE    EMS_30_ERR1
  1562.         JMP    SHORT EMS_30_S3
  1563. EMS_30_S2:    PUSH    AX            ;Read the system time using
  1564.         XOR    AH,AH            ;  bios int 1A function 00.
  1565.         INT    1AH
  1566.         MOV    AX,DX            ;copy low word of time
  1567.         INC    CX            ;multiply by high word. Inc
  1568.         MUL    CX            ;to assure count <> 0.
  1569.         MOV    OS_PASS_LOW,AX
  1570.         MOV    OS_PASS_HIGH,DX
  1571.         MOV    BX,AX                   ;Return password in BX,CX
  1572.         MOV    SS:[BP-2],DX        ;Update CX on stack
  1573.         POP    AX            ;get back subfunction
  1574. EMS_30_S3:    CMP    AL,2            ;return key function
  1575.         JNE    EMS_30_S4
  1576.         XOR    AX,AX            ;Clear return code
  1577.         MOV    OS_PASS_LOW,AX          ;Clear password
  1578.         MOV    OS_PASS_HIGH,AX
  1579.         MOV    OS_ENABLED,1        ;set op system flag
  1580.         JMP    SHORT EMS_30_EXIT
  1581. EMS_30_S4:    CMP    AL,1            ;Disable op system functions
  1582.         JNE    EMS_30_S5
  1583.         MOV    OS_ENABLED,0        ;Clear flag
  1584.         JMP    SHORT EMS_30_EXIT
  1585. EMS_30_S5:    OR    AL,AL            ;Enable op system functions
  1586.         JNE    EMS_30_ERR2
  1587.         MOV    OS_ENABLED,1        ;Set flag
  1588. EMS_30_EXIT:    XOR    AX,AX
  1589. EMS_30_EXIT1:    POP    DX
  1590.         RET
  1591. EMS_30_ERR1:    MOV    AH,0A4H            ;Access denied
  1592.         JMP    SHORT EMS_30_EXIT1
  1593. EMS_30_ERR2:    MOV    AH,8FH            ;Subfunction not defined
  1594.         JMP    SHORT EMS_30_EXIT1
  1595. EMS_30        ENDP
  1596. ;======================================================================
  1597. ;Unsupported Function
  1598. ;======================================================================
  1599. EMS_UNSP    PROC    NEAR
  1600.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  1601.         MOV    AH,91H            ;Feature not supported.
  1602.         RET
  1603. EMS_UNSP    ENDP
  1604. ;-----------------------------------------------------------------------------
  1605. ;Convert segment address into logical page number
  1606. ;Entry: ax - segment address to convert  EXIT: bl - logical page number
  1607. ;-----------------------------------------------------------------------------
  1608. EMS_SEG2LOG    PROC    NEAR
  1609.         ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
  1610.         PUSH    CX
  1611.         PUSH    DX
  1612.         XOR    BX,BX            ;clear logical sector number
  1613.         MOV    DX,CS:WINDOW_SEG
  1614.         MOV    CX,4
  1615. EMS_SEG2_L1:    CMP    AX,DX
  1616.         JE    EMS_SEG2_FND
  1617.         ADD    DX,400H
  1618.         INC    BX
  1619.         LOOP    EMS_SEG2_L1
  1620.         MOV    AH,8BH            ;segment not valid
  1621.         STC
  1622.         JMP    SHORT EMS_SEG2_EXIT
  1623. EMS_SEG2_FND:    CLC
  1624. EMS_SEG2_EXIT:    POP    DX
  1625.         POP    CX
  1626.         RET
  1627. EMS_SEG2LOG    ENDP
  1628. ;------------------------------------------------------------------------
  1629. ;EMS convert logical page to address
  1630. ;Entry: bx = logical page  dx = handle of page owner
  1631. ;Exit: dx,ax - absolute address of page. carry set - page not found
  1632. ;------------------------------------------------------------------------
  1633. EMS_LOG2PHY    PROC    NEAR
  1634.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  1635.         PUSH    DI
  1636.         MOV    DI,PAG_OWNER_TBL    ;Point to page owner table
  1637.         MOV    CX,TOTAL_PAGES        ;Check entry for each page
  1638. EMS_LOG2P_L1:    CMP    BYTE PTR [DI],DL    ;See if owned by handle
  1639.         JNE    EMS_LOG2P_S1
  1640.         CMP    WORD PTR [DI+1],BX    ;See if this is the page
  1641.         JE    EMS_LOG2P_S2        ;  we have been looking for.
  1642. EMS_LOG2P_S1:    ADD    DI,3
  1643.         LOOP    SHORT EMS_LOG2P_L1
  1644.         MOV    AH,8AH            ;page out of range for handle
  1645.         STC
  1646.         JMP    SHORT EMS_LOG2PHY_EXIT
  1647. EMS_LOG2P_S2:    SUB    DI,PAG_OWNER_TBL    ;compute the phy page address
  1648.         MOV    AX,DI
  1649.         XOR    DX,DX            ;Clear high word
  1650.         MOV    CX,3            ;Divide by size of each entry
  1651.         DIV    CX
  1652.         MOV    CX,16384        ;Mul page number by size of
  1653.         MUL    CX                      ;  page.
  1654.         ADD    AX,EXTEND_ADRL          ;Add starting address
  1655.         ADC    DL,EXTEND_ADRH
  1656.         XOR    DH,DH
  1657.         CLC                ;clear error flag
  1658. EMS_LOG2PHY_EXIT:
  1659.         POP    DI
  1660.         RET
  1661. EMS_LOG2PHY    ENDP
  1662. ;------------------------------------------------------------------------
  1663. ;EMS Assign pages  bx = number of pages needed  dx = handle to assign pages.
  1664. ;------------------------------------------------------------------------
  1665. EMS_ASSIGN    PROC    NEAR
  1666.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  1667.         CMP    AX,TOTAL_PAGES        ;see if enough total pages
  1668.         JG    EMS_ASSIGN_ERR2
  1669.         PUSH    DX            ;save handle
  1670.         PUSH    BX            ;save pages to add
  1671.         MOV    DX,0FFFFH        ;load unassigned handle
  1672.         CLC                             ;Get number of unassigned
  1673.         CALL    EMS_13                  ;  pages.
  1674.         POP    AX            ;Get back number of pages
  1675.         POP    DX            ;Get back handle
  1676.         CMP    BX,AX            ;are there enough pages?
  1677.         JL     EMS_ASSIGN_ERR1        ;No, return error code.
  1678.         PUSH    AX            ;Save number of pages to alloc
  1679.         CLC                ;Set handle found flag
  1680.         CALL    EMS_13            ;Get number of pages assigned
  1681.         POP    AX                      ;Get back num pages requested
  1682.         MOV    DI,PAG_OWNER_TBL    ;point to page owner table
  1683.         MOV    CX,TOTAL_PAGES        ;Get size of the array
  1684.         INC    CX            ;Make sure loop complete
  1685. EMS_ASSIGN_L1:    OR    AX,AX            ;See if we have assigned
  1686.         JE    EMS_ASSIGN_S2        ;  enough pages.
  1687.         CMP    BYTE PTR [DI],0FFH    ;see if page is unowned
  1688.         JNE    EMS_ASSIGN_S1        ;Page owned, try another.
  1689.         MOV    [DI],DL            ;if so, assign it to the hndl
  1690.         MOV    [DI+1],BX        ;Assign page number
  1691.         INC    BX            ;inc page number to assign
  1692.         DEC    AX            ;one less page needed.
  1693. EMS_ASSIGN_S1:    ADD    DI,3            ;point to the next page entry
  1694.         LOOP    EMS_ASSIGN_L1
  1695. EMS_ASSIGN_ERR1:
  1696.         MOV    AH,88H            ;not enough unallocated pages
  1697.         STC                ;set error flag
  1698.         JMP    SHORT EMS_ASSIGN_EXIT
  1699. EMS_ASSIGN_ERR2:
  1700.         MOV    AH,87H            ;not enough pages in system
  1701.         STC                ;set error flag
  1702.         JMP    SHORT EMS_ASSIGN_EXIT
  1703. EMS_ASSIGN_S2:    CLC
  1704.         XOR    AX,AX            ;Clear return code.
  1705. EMS_ASSIGN_EXIT:
  1706.         RET
  1707. EMS_ASSIGN    ENDP
  1708. ;------------------------------------------------------------------------
  1709. ;EMS Deallocate pages
  1710. ;Entry: dx = handle
  1711. ;       bl = number of pages to deallocate
  1712. ;------------------------------------------------------------------------
  1713. EMS_DEALLOC    PROC    NEAR
  1714.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  1715.         CMP    BL,0FFH            ;See if clear all
  1716.         JNE    EMS_DEALLOC_S0
  1717.         XOR    BX,BX
  1718.         JMP    SHORT EMS_DEALLOC_S1
  1719. EMS_DEALLOC_S0:    XOR    BH,BH
  1720.         PUSH    BX            ;Save num of pages to dealloc
  1721.         CLC
  1722.         CALL    EMS_13            ;Get num of pages owned
  1723.         POP    AX            ;Get back num pages to dealloc
  1724.         SUB    BX,AX            ;Sub dealloc from total
  1725. EMS_DEALLOC_S1:    MOV    DI,PAG_OWNER_TBL    ;Point to the page owner table
  1726.         MOV    CX,TOTAL_PAGES
  1727. EMS_DEALLOC_L1:    CMP    [DI],DL            ;compare handle
  1728.         JNE    EMS_DEALLOC_S2        ;if not, keep looking
  1729.         CMP    [DI+1],BX        ;compare page number if above
  1730.         JB     EMS_DEALLOC_S2        ;  new limit, erase.  Else,
  1731.         MOV    BYTE PTR [DI],0FFH    ;  keep looking
  1732.         MOV    WORD PTR [DI+1],0FFFFH
  1733. EMS_DEALLOC_S2:    ADD    DI,3            ;Point to next entry
  1734.         LOOP    EMS_DEALLOC_L1
  1735. EMS_DEALLOC_EXIT:
  1736.         XOR    AH,AH                   ;Clear return code.
  1737.         RET
  1738. EMS_DEALLOC    ENDP
  1739. ;-----------------------------------------------------------------------------
  1740. ;EMS Check Handle
  1741. ;Entry: dx = handle to check  Exit: zero flag set - handle not found, ah = 83h
  1742. ;-----------------------------------------------------------------------------
  1743. EMS_CHECK_HDL    PROC    NEAR
  1744.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  1745.         PUSH    DX
  1746.         PUSH    BX
  1747.         OR    DH,DH            ;dh must be 0 for valid handle
  1748.         JNE    EMS_CHECK_ERROR
  1749.         XCHG    AX,DX            ;Save ax
  1750.         MOV    AH,9            ;Convert handle into an index
  1751.         MUL    AH            ;  into the array
  1752.         MOV    BX,AX            ;copy to base register
  1753.         ADD    BX,HANDLE_ARRAY        ;add base address of array
  1754.         MOV    AX,DX            ;restore ax
  1755.         CMP    BYTE PTR [BX],0        ;If byte<>0, then good handle
  1756.         JE    EMS_CHECK_ERROR
  1757.         CLC                ;clear error flag
  1758. EMS_CHECK_EXIT:    POP    BX
  1759.         POP    DX
  1760.         RET
  1761. EMS_CHECK_ERROR:
  1762.         MOV    AH,83H            ;load error return code in ah
  1763.         STC                ;set error flag
  1764.         JMP    SHORT EMS_CHECK_EXIT
  1765. EMS_CHECK_HDL    ENDP
  1766. ;------------------------------------------------------------------------
  1767. ;EMS exchange page
  1768. ;Entry: bl = window page to map    dl,ax = absolute address of page to map.
  1769. ;------------------------------------------------------------------------
  1770. EMS_EXCH_PAG     PROC    NEAR
  1771.         ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
  1772.         PUSH    CX
  1773.         PUSH    SI
  1774.         PUSH    DS
  1775.         PUSH    ES
  1776.         PUSH    CS            ;point DS, ES to code segment
  1777.         POP    DS
  1778.         PUSH    CS
  1779.         POP    ES
  1780.         ASSUME DS:CODE,ES:CODE
  1781.          PUSH    DEST.BASE_ADRL       ;Save GTD data in case a
  1782.          PUSH    SOURCE.BASE_ADRL        ;  reentrant call is made.
  1783.          MOV    BH,DEST.BASE_ADRH
  1784.           PUSH    BX
  1785.          MOV    BH,SOURCE.BASE_ADRH
  1786.          PUSH    BX
  1787.         PUSH    AX            ;Save page address
  1788.         PUSH    DX
  1789.         XOR    BH,BH            ;Convert physical page number
  1790.         SAL    BX,1            ;  into an index,
  1791.         SAL    BX,1
  1792.          MOV    DI,OFFSET WINDOW_ADDR_BASE    ;Point to window addr
  1793.         MOV    SI,MAP_ARRAY_PTR    ;Point to mapping array.
  1794.         INC    SI
  1795.         INC    SI
  1796. ;Check to see if the address requested has already been mapped.
  1797.         PUSH    BX            ;Save offset into table
  1798.         MOV    DH,0FFH            ;Init local page flag.
  1799.         XOR    BX,BX                   ;Search the mapping table
  1800.         MOV    CX,4                    ;  for the address to be
  1801. EMS_EXCH_L1:    CMP    AX,[SI+BX]              ;  mapped. If found, use
  1802.         JNE    EMS_EXCH_S1             ;  the data from the mapped
  1803.         CMP    DL,[SI+BX+2]            ;  page since it may be more
  1804.         JE     EMS_EXCH_LOCAL          ;  accurate than the page
  1805. EMS_EXCH_S1:    ADD    BX,4            ;  in extended memory.
  1806.         LOOP    EMS_EXCH_L1
  1807.         JMP    SHORT EMS_EXCH_S2    ;Local page not found
  1808. EMS_EXCH_LOCAL:    MOV    AX,[SI+BX]        ;Replace new page address with
  1809.         MOV    DL,[SI+BX+2]            ;  local page address.
  1810.                   MOV    DH,BL            ;Save local page index.
  1811. EMS_EXCH_S2:    POP    BX            ;Get original page index
  1812.         CMP    BL,DH            ;See if we are remapping page
  1813.         JNE    EMS_EXCH_S3          ;If different, continue
  1814.          ADD    SP,4            ;Clean up stack
  1815.         JMP    SHORT EMS_EXCH_EXIT    ;If same page, skip everything
  1816. ;Save page currently mapped.
  1817. EMS_EXCH_S3:    PUSH    AX                      ;Save new page address
  1818.         PUSH    DX
  1819.         MOV     AX,[SI+BX]              ;Load address of current page
  1820.         MOV     DL,[SI+BX+2]            ;  into destination registers.
  1821.         OR    AX,AX            ;If the current page is
  1822.         JNE    STORE_PAGE        ;  unowned, don't save it.
  1823.         OR    DL,DL
  1824.         JE    LOAD_PAGE
  1825. STORE_PAGE:     MOV     CX,[DI+BX]              ;Load physical page address
  1826.         MOV     DH,[DI+BX+2]            ;  into source registers.
  1827.                CALL    EMS_MOVE_DATA
  1828. ;Load in page from extended memory.
  1829. LOAD_PAGE:     POP    DX            ;Pop new page address into
  1830.         POP    CX                      ;  source registers.
  1831.         MOV    DH,DL
  1832.         CLI                ;Critical code, no interrupts
  1833.         POP    AX            ;Get back original destination
  1834.         MOV     [SI+BX+2],AL            ;  address.
  1835.         POP     AX            ;Load address of new page into
  1836.         MOV     [SI+BX],AX        ;  page map array.
  1837.         OR    CX,CX            ;If the current page is
  1838.         JNE    EMS_EXCH_S4        ;  unowned, don't save it.
  1839.         OR    DH,DH
  1840.         JE    EMS_EXCH_EXIT
  1841. EMS_EXCH_S4:     MOV    AX,[DI+BX]             ;Get window address again.
  1842.         MOV    DL,[DI+BX+2]
  1843.                 CALL    EMS_MOVE_DATA        ;Move memory
  1844. EMS_EXCH_EXIT:    STI                ;All clear, allow interrupts
  1845.                   POP     BX                      ;Restore GDT data
  1846.           MOV    SOURCE.BASE_ADRH,BH
  1847.          POP     BX
  1848.           MOV    DEST.BASE_ADRH,BH
  1849.          POP     SOURCE.BASE_ADRL
  1850.                   POP     DEST.BASE_ADRL
  1851.         POP    ES            ;Restore registers
  1852.         POP    DS
  1853.         POP    SI
  1854.         POP    CX
  1855.         RET
  1856. EMS_EXCH_PAG     ENDP
  1857. ;-----------------------------------------------------------------------------
  1858. ;EMS MOVE DATA moves blocks of data using BIOS move block function.
  1859. ;  Entry:  DL,AX - destination address  CX,DH - source address.
  1860. ;-----------------------------------------------------------------------------
  1861. EMS_MOVE_DATA    PROC    NEAR
  1862.         PUSH    SI
  1863.         MOV    SI,OFFSET GDT        ;ES:SI point to GDT
  1864.         MOV    DEST.BASE_ADRL,AX    ;store source address
  1865.         MOV    DEST.BASE_ADRH,DL
  1866.         MOV    SOURCE.BASE_ADRL,CX    ;store destination address
  1867.         MOV    SOURCE.BASE_ADRH,DH
  1868.         MOV    AH,87H            ;BIOS move extended block
  1869.         MOV    CX,2000H        ;move 8192 words
  1870.         INT    15H            ;call BIOS
  1871.         POP    SI
  1872.         RET
  1873. EMS_MOVE_DATA    ENDP
  1874. ;-----------------------------------------------------------------------------
  1875. ;Init1. code initializes memory below this address then returns.
  1876. ;-----------------------------------------------------------------------------
  1877. INITIALIZE1    PROC    NEAR
  1878. INIT1:        ASSUME    CS:CODE,DS:CODE,ES:CODE
  1879.         MOV    DI,PAG_OWNER_TBL
  1880.         MOV    AX,TOTAL_PAGES      ;Compute size of page owner
  1881.         MOV    DX,3                    ;  table.
  1882.         MUL    DX
  1883.         MOV    CX,AX
  1884.         XOR    AX,AX                   ;load ff's into page owner tbl
  1885.         DEC    AX                      ;  because ff is invalid hndl.
  1886.         REP    STOSB
  1887.         MOV    AX,TOTAL_HANDLES    ;Compute size of handle array
  1888.         MOV    AH,9            ;9 bytes / handle
  1889.         MUL    AH
  1890.         MOV    CX,AX
  1891.         ADD    CX,36            ;Add room for context save
  1892.         XOR    AX,AX                   ;  area.
  1893.         REP    STOSW
  1894.         MOV    DI,HANDLE_ARRAY        ;activate system handle
  1895.         DEC    BYTE PTR [DI]
  1896.         RET
  1897. INITIALIZE1    ENDP
  1898. ;======================  End of resident Code  =============================
  1899. DATA_START    =    $
  1900. VDISK_HEADER     DB    'VDISK  V'
  1901. ERRMSG        DB    'Not enough memory',13,10,'$'
  1902. ;===========================================================================
  1903. ;Initialize. This routine sets up the EMS driver.
  1904. ;===========================================================================
  1905. INITIALIZE    PROC    NEAR
  1906.         ASSUME CS:CODE,DS:CODE,ES:NOTHING
  1907.         PUSH    CS            ;Parse command line
  1908.         POP    ES
  1909.         LDS    SI,[REQ_HEADADR]    ;get back addr of hdr
  1910.         ASSUME    DS:NOTHING,ES:CODE
  1911.         LDS    SI,DS:[SI.CONFIG_PTR]   ;Get pointer to config line
  1912.         MOV    BH,1            ;Look for first non-character
  1913.         MOV    CX,80            ;80 characters in line
  1914.         CALL    SCAN_FOR                ;Scan for non-character.
  1915.          OR    AH,AH            ;see if found
  1916.         JNE    CHK_FOR_VDISK        ;not found, skip remainder
  1917.         XOR    BH,BH            ;Look for next character
  1918.         CALL    SCAN_FOR        ;Scan for character
  1919.          OR    AH,AH            ;see if found
  1920.         JNE    CHK_FOR_VDISK        ;not found, skip remainder
  1921. ;-----------------------------------------------------------------------------
  1922. ;Non-blank line after driver name. Attempt to convert to memory size in Kbytes
  1923. ;-----------------------------------------------------------------------------
  1924.         DEC    SI            ;backup to 1st number
  1925.         MOV    CX,5            ;Max 5 numbers.
  1926.         XOR    AX,AX            ;Clear running total
  1927.         MOV    DI,10            ;Decimal conversion constant
  1928. INIT_LOOP1:     MOV     BL,DS:[SI]        ;Get number
  1929.         INC    SI            ;Point to next number.
  1930.         SUB    BL,'0'                  ;Convert to number and see
  1931.         JB      INIT_SKIP1              ;  if in range for a number.
  1932.         CMP    BL,9
  1933.         JA      INIT_SKIP1
  1934.         XOR    BH,BH
  1935.         MUL    DI              ;Mul by 16 to convert to hex
  1936.         ADD    AX,BX            ;add to current total
  1937.         LOOP    INIT_LOOP1
  1938. ;-----------------------------------------------------------------------------
  1939. ;Compute number of pages available for allocated memory.
  1940. ;-----------------------------------------------------------------------------
  1941. INIT_SKIP1:    XOR    DX,DX            ;Clear high word for divide
  1942.         MOV    DI,16                   ;Divide number of Kbytes
  1943.         DIV    DI                      ;  by 16 Kbytes / page.
  1944.         OR    AX,AX            ;if number less than 1 page
  1945.         JE     CHK_FOR_VDISK        ;  use default 24 pages.
  1946.         MOV    CS:TOTAL_PAGES,AX    ;Save number of pages.
  1947. ;-----------------------------------------------------------------------------
  1948. ;Check for vdisk driver by reading int 19 vector.
  1949. ;-----------------------------------------------------------------------------
  1950. CHK_FOR_VDISK:    PUSH    CS            ;Set DS = CS
  1951.         POP    DS
  1952.         ASSUME     DS:CODE
  1953.         MOV    AX,3519H        ;Get interrupt vector 19
  1954.         INT    21H            ;ES points to VDISK segment
  1955.         MOV    DI,12H            ;VDISK header at offset 12h
  1956.         MOV    SI,OFFSET VDISK_HEADER
  1957.         MOV    CX,8            ;8 characters in header
  1958.         XOR    BX,BX            ;assume no memory used by vdisk
  1959.         REPE    CMPSB            ;Compare header
  1960.         JNE     CHK_EXT_MEM
  1961. ;-----------------------------------------------------------------------------
  1962. ;If VDISK present, read top of available memory from inside VDISK driver.
  1963. ;-----------------------------------------------------------------------------
  1964.         MOV    SI,2CH            ;load offset of memory used
  1965.         MOV    AX,ES:[SI]        ;Get amount of memory used by
  1966.         MOV    DL,ES:[SI+2]        ;  vdisk
  1967.         SUB    DL,10H            ;Subtract 1 Mbyte starting adr
  1968.         XOR    DH,DH
  1969.         MOV    BX,16384        ;Convert to 16k pages
  1970.         DIV    BX
  1971.         MOV    BX,AX            ;save result in BX
  1972. ;-----------------------------------------------------------------------------
  1973. ;Find upper limit of extended memory.
  1974. ;-----------------------------------------------------------------------------
  1975. CHK_EXT_MEM:    PUSH    CS            ;ES = CS
  1976.         POP    ES
  1977.         ASSUME    ES:CODE
  1978.         MOV    AH,88H            ;Get extended memory function
  1979.         CLC                ;clr err flag. (fix IBMCACHE)
  1980.         INT    15H            ;Returns extended memory in
  1981.         JC     EXTEND_ERROR         ;  1k pages.
  1982.         MOV    CL,4            ;Convert number of 1k pages
  1983.         SAR    AX,CL            ;  into number of 16k pages.
  1984.         SUB    AX,TOTAL_PAGES        ;See if there is enough room.
  1985.         JL    EXTEND_ERROR
  1986.         CMP    AX,BX            ;Subtract memory used by vdisk
  1987.         JGE    EXTEND_MEM_OK1
  1988. EXTEND_ERROR:    JMP    DISP_ERR        ;Error, abort instalation.
  1989. ;-----------------------------------------------------------------------------
  1990. ;Compute the starting address of the extended memory area for int 15.
  1991. ;-----------------------------------------------------------------------------
  1992. EXTEND_MEM_OK1:    PUSH    CS                      ;  ES = CS
  1993.         POP    ES                      ;Convert memory req. to 1k
  1994.         ASSUME    ES:CODE                 ;  pages then store this
  1995.         MOV    CL,4                    ;  value for use as the new
  1996.         SAL    AX,CL                   ;  extended memory limit.
  1997.         MOV    EXT_MEM_LIMIT,AX
  1998.         MOV    CX,1024            ;Convert number of 1024
  1999.                 MUL    CX                      ;  byte pages to absolute adr
  2000.         ADD    DL,10H                  ;Add starting address of
  2001.         MOV    EXTEND_ADRL,AX          ;  extended memory and
  2002.         MOV    EXTEND_ADRH,DL          ;  save.
  2003. ;-----------------------------------------------------------------------------
  2004. ;Initialize the variables and pointers needed to emulate the EMS spec.
  2005. ;-----------------------------------------------------------------------------
  2006.         MOV    BX,OFFSET DATA_START    ;Get end of installed code.
  2007.         MOV    PAG_OWNER_TBL,BX    ;Save pointer to page table
  2008.         MOV    AX,TOTAL_PAGES          ;Get number of pages
  2009.         MOV    DX,3
  2010.         MUL    DX
  2011.         ADD    AX,BX               ;Add to current pointer
  2012.         MOV    HANDLE_ARRAY,AX         ;Save pointer to handle array
  2013.         MOV    CX,AX            ;save current position
  2014.         MOV    AX,TOTAL_HANDLES    ;compute size of handle
  2015.         MOV    AH,9                    ;  array using 9 bytes / hdl.
  2016.         MUL    AH
  2017.         ADD    AX,CX
  2018.         MOV    MAP_ARRAY_PTR,AX    ;map array 18 bytes. 4 arrays.
  2019.         ADD    AX,72+15                ;Arrays + 15 to next segment.
  2020. ;-----------------------------------------------------------------------------
  2021. ;Compute the memory requirments for driver.
  2022. ;-----------------------------------------------------------------------------
  2023.         MOV    CL,4            ;Convert offset into a
  2024.         SHR    AX,CL            ;  segment value
  2025.         MOV    BX,CS            ;Get code segment
  2026.         ADD    AX,BX            ;Add code segment to code length
  2027.         MOV    WINDOW_SEG,AX        ;Store starting segment of ems
  2028.         PUSH    AX
  2029. ;-----------------------------------------------------------------------------
  2030. ;Generate and store abolute addresses of window pages.
  2031. ;-----------------------------------------------------------------------------
  2032.         MOV    DX,16            ;Convert segment into
  2033.         MUL    DX                      ;  absolute address.
  2034.         MOV    DI,OFFSET WINDOW_ADDR_BASE
  2035.         MOV    CX,4
  2036. EMS_INIT_L2:    MOV    [DI],AX            ;Save absolute address
  2037.         MOV    [DI+2],DX
  2038.         ADD    AX,16384                ;Point to next page address
  2039.         ADC    DX,0
  2040.         ADD    DI,4                 ;Point to next save address
  2041.         LOOP    EMS_INIT_L2
  2042. ;-----------------------------------------------------------------------------
  2043. ;Write the memory requirments to the device driver header
  2044. ;-----------------------------------------------------------------------------
  2045.         POP    BX                    ;Get back seg start of window
  2046.         ADD    BX,1000H                ;Add 64 Kbytes.
  2047.         XOR    AX,AX            ;Start at offset 0
  2048.         PUSH    ES
  2049.         CALL    LOAD_HEADER          ;Load memory requirments into
  2050.         POP    ES                      ;  request header.
  2051.         MOV    DX,OFFSET PROGRAM    ;Print copyright
  2052.         MOV    AH,9
  2053.         INT    21H
  2054. ;-----------------------------------------------------------------------------
  2055. ;Vector interrupt 15h to reserve the extended memory.
  2056. ;-----------------------------------------------------------------------------
  2057.         PUSH    ES
  2058.         MOV    AX,3515H        ;Get interrupt vector 15
  2059.         INT    21H
  2060.         MOV    OLD_INT15HO,BX        ;save vector
  2061.         MOV    OLD_INT15HS,ES
  2062.         POP    ES
  2063.         MOV    AX,2515H        ;Set interrupt vector 15
  2064.         MOV    DX,OFFSET INT_15H
  2065.         INT    21H            ;Call DOS
  2066. ;-----------------------------------------------------------------------------
  2067. ;Vector the 67h interrupt to the driver. Jump to final installation code.
  2068. ;-----------------------------------------------------------------------------
  2069.         MOV    AX,2567H        ;Set interrupt vector 67
  2070.         MOV    DX,OFFSET INT_67H
  2071.         INT    21H            ;Call DOS
  2072.         JMP    INIT1            ;jump to final init. code.
  2073. ;-----------------------------------------------------------------------------
  2074. ;error routine to abort instalation.
  2075. ;-----------------------------------------------------------------------------
  2076. DISP_ERR:    MOV    DX,OFFSET ERRMSG    ;Tell user that the driver is
  2077.         MOV    AH,9            ;  not loaded.
  2078.         INT    21H
  2079.         MOV    AX,3000H        ;Get DOS version
  2080.         INT    21H
  2081.         XCHG    AL,AH            ;Put number in proper order
  2082.         CMP    AX,31EH            ;See if DOS 3.3
  2083.         MOV    AX,OFFSET DRIVER_END    ;Offset of device driver code
  2084.         MOV    BX,CS               ;If >3.3, abort install with
  2085.         JB     ERROR_ABORT_SKIP    ; 0 memory. Otherwise leave
  2086.         XOR    AX,AX            ;  driver stub installed.
  2087. ERROR_ABORT_SKIP:
  2088.         CALL    LOAD_HEADER        ;Load into request header
  2089.         MOV    AX,8002             ;Indicate error in the
  2090.         RET                ;  driver return code.
  2091. ;-----------------------------------------------------------------------------
  2092. ;LOADHEADER loads the amount of memory needed into the request header.
  2093. ;-----------------------------------------------------------------------------
  2094. LOAD_HEADER    PROC    NEAR
  2095.         LES    DI,[REQ_HEADADR]        ;get addr of req hdr
  2096.         MOV    WORD PTR ES:[DI.ADDRESS],AX    ;Store offset and
  2097.         MOV    WORD PTR ES:[DI.ADDRESS+2],BX   ;  code segment.
  2098.         RET
  2099. LOAD_HEADER    ENDP
  2100. ;-----------------------------------------------------------------------------
  2101. ;ScanFor - scans for first (non)occurance of character in line.
  2102. ; Entry -  BH - 0 = scan for non character, 1 = scan for character.
  2103. ;          DS:SI - string to scan.   CX - length of string
  2104. ; Exit  -  AH - 1 = end of line found.
  2105. ;-----------------------------------------------------------------------------
  2106. SCAN_FOR    PROC    NEAR
  2107.         XOR    AH,AH               ;Clear found flag
  2108. SCAN_LOOP1:    LODSB                ;Get character
  2109.         OR    BH,BH            ;see if first match or
  2110.         JE    SCAN_SKIP1        ;  mismatch. 0 = match
  2111.         CMP    AL,20H                  ;Check for noncharacter.
  2112.         JLE    SCAN_SKIP4
  2113.         JMP    SHORT SCAN_SKIP2
  2114. SCAN_SKIP1:    CMP    AL,20H            ;Check for character
  2115.         JG     SCAN_SKIP4
  2116. SCAN_SKIP2:    CMP    AL,13            ;Check for CR
  2117.         JE    SCAN_SKIP3
  2118.         CMP    AL,10            ;Check for LF
  2119.         JE    SCAN_SKIP3
  2120.         LOOP    SCAN_LOOP1
  2121. SCAN_SKIP3:    INC    AH            ;character not found
  2122. SCAN_SKIP4:    RET
  2123. SCAN_FOR    ENDP
  2124. END_OF_CODE    =    $
  2125. INITIALIZE    ENDP
  2126. CODE        ENDS
  2127.         END
  2128.